2022-07-31:给出一个有n个点,m条有向边的图,
你可以施展魔法,把有向边,变成无向边,
比如A到B的有向边,权重为7。施展魔法之后,A和B通过该边到达彼此的代价都是7。
求,允许施展一次魔法的情况下,1到n的最短路,如果不能到达,输出-1。
n为点数, 每条边用(a,b,v)表示,含义是a到b的这条边,权值为v。
点的数量 <= 10^5,边的数量 <= 2 * 10^5,1 <= 边的权值 <= 10^6。
来自网易。

答案2022-07-31:

单元路径最短算法。dijkstra算法。
点扩充,边扩充。

代码用rust编写。代码如下:

use rand::Rng;
fn main() {let nn: i32 = 20;let vv: i32 = 30;let test_time: i32 = 2000;println!("测试开始");for _ in 0..test_time {let n = rand::thread_rng().gen_range(0, nn) + 2;let mut roads = random_roads(n, vv);let ans1 = min1(n, &mut roads);let ans2 = min2(n, &mut roads);if ans1 != ans2 {println!("ans1 = {}", ans1);println!("ans2 = {}", ans2);println!("roads = {:?}", roads);println!("出错了!");break;}}println!("测试结束");
}// 为了测试
// 相对暴力的解
// 尝试每条有向边,都变一次无向边,然后跑一次dijkstra算法
// 那么其中一定有最好的答案
fn min1(n: i32, roads: &mut Vec<Vec<i32>>) -> i32 {let mut ans = 2147483647;for i in 0..roads.len() as i32 {let mut graph: Vec<Vec<Vec<i32>>> = vec![];for _ in 0..=n {graph.push(vec![]);}graph[roads[i as usize][1] as usize].push(vec![roads[i as usize][0], roads[i as usize][2]]);for r in roads.iter() {graph[r[0] as usize].push(vec![r[1], r[2]]);}ans = get_min(ans, dijkstra1(n, &mut graph));}return if ans == 2147483647 { -1 } else { ans };
}fn get_min<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {if a < b {a} else {b}
}fn dijkstra1(n: i32, graph: &mut Vec<Vec<Vec<i32>>>) -> i32 {let mut heap: Vec<Vec<i32>> = vec![];let mut visited: Vec<bool> = vec![];for _ in 0..n + 1 {visited.push(false);}heap.push(vec![1, 0]);let mut ans = 2147483647;while heap.len() > 0 {heap.sort_by(|a, b| (b[1].cmp(&a[1])));let cur = heap.pop().unwrap();if cur[0] == n {ans = cur[1];break;}if visited[cur[0] as usize] {continue;}visited[cur[0] as usize] = true;for edge in graph[cur[0] as usize].iter() {let to = edge[0];let weight = edge[1];if !visited[to as usize] {heap.push(vec![to, cur[1] + weight]);}}}return ans;
}// 最优解
// 时间复杂度O(N * logN)
// N <= 2 * 10^5
fn min2(n: i32, roads: &mut Vec<Vec<i32>>) -> i32 {let mut graph: Vec<Vec<Vec<i32>>> = vec![];for _ in 0..=n {graph.push(vec![]);}for r in roads.iter() {graph[r[0] as usize].push(vec![0, r[1], r[2]]);graph[r[1] as usize].push(vec![1, r[0], r[2]]);}let mut heap: Vec<Vec<i32>> = vec![];let mut visited: Vec<Vec<bool>> = vec![];for i in 0..2 {visited.push(vec![]);for _ in 0..n + 1 {visited[i as usize].push(false);}}// a -> 0,a   1,a// boolean[] visted = new boolean[n+1]// visted[i] == true 去过了!从队列里弹出来过了!以后别碰了!// visted[i] == false 没去过!第一次从队列里弹出来!当前要处理!// 0,1,0 -> 之前没有走过魔法路,当前来到1号出发点,代价是0heap.push(vec![0, 1, 0]);let mut ans = 2147483647;while heap.len() > 0 {heap.sort_unstable_by(|a, b|b[2].cmp(&a[2]));let cur = heap.pop().unwrap();if visited[cur[0] as usize][cur[1] as usize] {continue;}visited[cur[0] as usize][cur[1] as usize] = true;if cur[1] == n {ans = get_min(ans, cur[2]);if visited[0][n as usize] && visited[1][n as usize] {break;}}for edge in graph[cur[1] as usize].iter() {// 当前来到cur// 之前有没有走过魔法路径:cur[0] == 0 ,没走过!cur[0] = 1, 走过了// 当前来到的点是啥,cur[1],点编号!// 之前的总代价是啥?cur[2]// cur,往下,能走的,所有的路在哪?// 当前的路,叫edge// 当前的路,是不是魔法路!edge[0] = 0 , 不是魔法路// edge[0] == 1,是魔法路// cur[0] + edge[0] == 0// 路 :0 5 20// 当前路,不是魔法路,去往的点是5号点,该路权重是20// 路 :1 7 13// 当前路,是魔法路,去往的点是7号点,该路权重是13if cur[0] + edge[0] == 0 {if !visited[0][edge[1] as usize] {heap.push(vec![0, edge[1], cur[2] + edge[2]]);}}// cur[0] + edge[0] == 1// 0         1// 1         0if cur[0] + edge[0] == 1 {if !visited[1][edge[1] as usize] {heap.push(vec![1, edge[1], cur[2] + edge[2]]);}}// 1 1 == 2}}return if ans == 2147483647 { -1 } else { ans };
}// 为了测试
fn random_roads(n: i32, v: i32) -> Vec<Vec<i32>> {let m = rand::thread_rng().gen_range(0, n * (n - 1) / 2) + 1;let mut roads: Vec<Vec<i32>> = vec![];for i in 0..m {roads.push(vec![]);for _ in 0..3 {roads[i as usize].push(0);}}for i in 0..m {roads[i as usize][0] = rand::thread_rng().gen_range(0, n) + 1;roads[i as usize][1] = rand::thread_rng().gen_range(0, n) + 1;roads[i as usize][2] = rand::thread_rng().gen_range(0, v) + 1;}return roads;
}

执行结果如下:

代码用go编写。代码如下:

package mainimport ("fmt""math/rand""sort""time"
)func main() {rand.Seed(time.Now().Unix())N := 20V := 30testTime := 2000fmt.Println("测试开始")for i := 0; i < testTime; i++ {n := rand.Intn(N) + 2roads := randomRoads(n, V)ans1 := min1(n, roads)ans2 := min2(n, roads)if ans1 != ans2 {fmt.Println("出错了!")fmt.Println("roads = ", roads)fmt.Println("ans1 = ", ans1)fmt.Println("ans2 = ", ans2)fmt.Println("-----------")break}}fmt.Println("测试结束")
}// 为了测试
// 相对暴力的解
// 尝试每条有向边,都变一次无向边,然后跑一次dijkstra算法
// 那么其中一定有最好的答案
func min1(n int, roads [][]int) int {ans := 2147483647for i := 0; i < len(roads); i++ {graph := make([][][]int, 0)for j := 0; j <= n; j++ {graph = append(graph, make([][]int, 0))}graph[roads[i][1]] = append(graph[roads[i][1]], []int{roads[i][0], roads[i][2]})for _, r := range roads {graph[r[0]] = append(graph[r[0]], []int{r[1], r[2]})}ans = getMin(ans, dijkstra1(n, graph))}if ans == 2147483647 {return -1} else {return ans}
}func getMin(a, b int) int {if a < b {return a} else {return b}
}func dijkstra1(n int, graph [][][]int) int {heap0 := make([][]int, 0)visited := make([]bool, n+1)heap0 = append(heap0, []int{1, 0})ans := 2147483647for len(heap0) > 0 {sort.Slice(heap0, func(i, j int) bool {a := heap0[i]b := heap0[j]return a[1] < b[1]})cur := heap0[0]heap0 = heap0[1:]if cur[0] == n {ans = cur[1]break}if visited[cur[0]] {continue}visited[cur[0]] = truefor _, edge := range graph[cur[0]] {to := edge[0]weight := edge[1]if !visited[to] {heap0 = append(heap0, []int{to, cur[1] + weight})}}}return ans
}// 最优解
// 时间复杂度O(N * logN)
// N <= 2 * 10^5
func min2(n int, roads [][]int) int {graph := make([][][]int, 0)for j := 0; j <= n; j++ {graph = append(graph, make([][]int, 0))}for _, r := range roads {graph[r[0]] = append(graph[r[0]], []int{0, r[1], r[2]})graph[r[1]] = append(graph[r[1]], []int{1, r[0], r[2]})}heap0 := make([][]int, 0)visited := make([][]bool, 2)for i := 0; i < 2; i++ {visited[i] = make([]bool, n+1)}// a -> 0,a   1,a// boolean[] visted = new boolean[n+1]// visted[i] == true 去过了!从队列里弹出来过了!以后别碰了!// visted[i] == false 没去过!第一次从队列里弹出来!当前要处理!// 0,1,0 -> 之前没有走过魔法路,当前来到1号出发点,代价是0heap0 = append(heap0, []int{0, 1, 0})ans := 2147483647for len(heap0) > 0 {sort.Slice(heap0, func(i, j int) bool {a := heap0[i]b := heap0[j]return a[2] < b[2]})cur := heap0[0]heap0 = heap0[1:]if visited[cur[0]][cur[1]] {continue}visited[cur[0]][cur[1]] = trueif cur[1] == n {ans = getMin(ans, cur[2])if visited[0][n] && visited[1][n] {break}}for _, edge := range graph[cur[1]] {// 当前来到cur// 之前有没有走过魔法路径:cur[0] == 0 ,没走过!cur[0] = 1, 走过了// 当前来到的点是啥,cur[1],点编号!// 之前的总代价是啥?cur[2]// cur,往下,能走的,所有的路在哪?// 当前的路,叫edge// 当前的路,是不是魔法路!edge[0] = 0 , 不是魔法路// edge[0] == 1,是魔法路// cur[0] + edge[0] == 0// 路 :0 5 20// 当前路,不是魔法路,去往的点是5号点,该路权重是20// 路 :1 7 13// 当前路,是魔法路,去往的点是7号点,该路权重是13if cur[0]+edge[0] == 0 {if !visited[0][edge[1]] {heap0 = append(heap0, []int{0, edge[1], cur[2] + edge[2]})}}// cur[0] + edge[0] == 1// 0         1// 1         0if cur[0]+edge[0] == 1 {if !visited[1][edge[1]] {heap0 = append(heap0, []int{1, edge[1], cur[2] + edge[2]})}}// 1 1 == 2}}if ans == 2147483647 {return -1} else {return ans}
}// 为了测试
func randomRoads(n, v int) [][]int {m := rand.Intn(int(n*(n-1)/2)) + 1roads := make([][]int, m)for i := 0; i < m; i++ {roads[i] = make([]int, 3)}for i := 0; i < m; i++ {roads[i][0] = rand.Intn(n) + 1roads[i][1] = rand.Intn(n) + 1roads[i][2] = rand.Intn(v) + 1}return roads
}

执行结果如下:


左神java代码

2022-07-31:给出一个有n个点,m条有向边的图, 你可以施展魔法,把有向边,变成无向边, 比如A到B的有向边,权重为7。施展魔法之后,A和B通过该边到达彼此的代价都是7。 求,允许施展一次魔法相关推荐

  1. 信奥学习规划 信息学竞赛之路(2022.07.31)

    信奥(CSP-J/S初赛)公益讲座精选系列之考试形式介绍 信奥(CSP-J/S初赛)公益讲座精选系列之考试形式介绍_哔哩哔哩_bilibili 2022年信息学奥赛学习规划讲座 2022年信息学奥赛学 ...

  2. 如何弹出一个模式窗口来显示进度条 .

    最近看了好多人问这方面的问题,以前我也写过一篇blog,里面说了如何在子线程中控制进度条.但目前大多数环境,需要弹出模式窗口,来显示进度条,那么只需要在原先的基础上稍作修改即可. 首先是进度条窗体,需 ...

  3. 信奥中的数学学习资料汇总(2022.10.31)

    信奥中的数学之入门组(面向小学四年级至六年级以及初一学生) 信奥中的数学之入门组(面向小学四年级至六年级以及初一学生)_dllglvzhenfeng的博客-CSDN博客 信奥中的数学学习:小学.初高中 ...

  4. ​运动健身APP开发软件,帮助您锻炼出一个理想身材​

    ​运动健身APP开发软件,帮助您锻炼出一个理想身材​. 1.解决网上健身烦恼,运动健身APP提供了丰富的教程资源,用户没有太多时间或只想在网上锻炼,也可以通过网上享受健身服务.视频教程,图形教程,健身 ...

  5. 下了31个markdown编辑器,我就不信选不出一个好用的

    markdown编辑器测评 标准 总体标准 渲染领域 编辑领域 数据管理 其他 Typora Vnote Mweb Joplin Zettlr macdown ulysses Marktext gho ...

  6. 《LeetCode力扣练习》第31题 下一个排列 Java

    <LeetCode力扣练习>第31题 下一个排列 Java 一.资源 题目: 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列. 例如,arr = [1,2,3] ,以下这些都可 ...

  7. 挖出一个面试刷题的宝藏资源,赶紧收下了~

    挖出一个面试题宝藏公众号,收集了大量的实用面试题,感觉很有用,这些题目分享给大家,需要的同学可以刷两遍 1-10期 [10期]Redis 面试常见问答 [09期]说说hashCode() 和 equa ...

  8. 用好这 42 款 Chrome 插件,每年轻松省出一个年假(附下载)

    来源:码农有道 本文约3700字,建议阅读8分钟. 为了更好地使用谷歌浏览器,最近小编整理了一些常用的谷歌插件,分享给大家. 前言 相信很多人都在使用 Chrome 浏览器,其流畅的浏览体验得到了不少 ...

  9. 平面上给定n条线段,找出一个点,使这个点到这n条线段的距离和最小。

    题目:平面上给定n条线段,找出一个点,使这个点到这n条线段的距离和最小. 源码如下: 1 #include <iostream> 2 #include <string.h> 3 ...

最新文章

  1. C++: int int int * int**的区别、联系和用途
  2. 对反向传播算法(Back-Propagation)的推导与一点理解
  3. php数组逗号连接,php – 如何使用逗号组合数组中的所有元素?
  4. router锚点和html锚点,hash模式下Vue-router页面返回锚点(scroll behavior)实现
  5. 七乐彩中奖规则表_【开奖】双色球第2020094期开奖结果出炉!你中奖了吗?
  6. 沥青防水卷材行业调研报告 - 市场现状分析与发展前景预测
  7. Klevgrand DAW LP for Mac(乙烯基唱片播放器模拟插件)
  8. 7种超粗体字体(带有示例)
  9. linux程序设计第四版中文pdf下载地址
  10. 零至二岁宝宝故事(一)
  11. APP在推广之渠道为王(三 )
  12. 利用js文件获取视频文件详细信息 如帧速率、总比特率等
  13. [论文笔记|VIO]On the Comparison of Gauge Freedom Handling in Optimization-based V-I State Estimation
  14. 大白菜U盘重装Win10系统教程
  15. MDM9607 SE1801A安全芯片调试记录
  16. 技术水平:了解、熟悉、精通各是什么意思以及如何深入研究一门技术
  17. eclipse官网32位下载地址
  18. [Vue warn]: Invalid vnode type when creating vnode: .
  19. LCD屏幕调试过程(驱动IC ST7701s)
  20. android 服务自动运行怎么办,怎么解决安卓软件服务停止后又自启?

热门文章

  1. 放大电路中的反馈(二)负反馈对放大电路影响
  2. Cesium 通过scaleByDistance设置远小近大的广告牌图形视觉效果
  3. 2021年亚太地区15个最佳职场榜单;人均养老消费预期将超百万元;高净值人群财富传承方式依然首选保险 | 美通社头条...
  4. linux gpu 风扇速度,如何在无头节点上调整NVIDIA GPU风扇速度?
  5. 通俗易懂:Nginx正反向代理,买瓶可乐就能理解
  6. 数据结构3_160805无头单向不循环
  7. 想让微信公众号文章上“朋友圈热文”?看看这个
  8. 一个金融网站的SEO优化技巧案例
  9. 雷达系列论文翻译(六):LIO-SAM
  10. CVPR 2022 | 浙大提出Oriented RepPoints:旋转目标检测网络