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号出发点,代价是0
heap.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号点,该路权重是13
if 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 0
if 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 main

import (
"fmt"
"math/rand"
"sort"
"time"
) func main() {
rand.Seed(time.Now().Unix())
N := 20
V := 30
testTime := 2000
fmt.Println("测试开始")
for i := 0; i < testTime; i++ {
n := rand.Intn(N) + 2
roads := 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 := 2147483647
for 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 := 2147483647
for 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]] = true
for _, 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号出发点,代价是0
heap0 = append(heap0, []int{0, 1, 0})
ans := 2147483647
for 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]] = true
if 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号点,该路权重是13
if 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 0
if 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)) + 1
roads := 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) + 1
roads[i][1] = rand.Intn(n) + 1
roads[i][2] = rand.Intn(v) + 1
}
return roads
}

执行结果如下:


左神java代码

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

  1. 31、下一个排列 | 算法(leetode,附思维导图 + 全部解法)300题

    零 标题:算法(leetode,附思维导图 + 全部解法)300题之(31)下一个排列 一 题目描述 二 解法总览(思维导图) 三 全部解法 1 方案1 1)代码: // 方案1 "双指针法 ...

  2. ZT CSDN 如何以最快的速度计算出一个二进制数中1的个数? [

    一道算法面试题:如何以最快的速度计算出一个二进制数中1的个数? [问题点数:10分,结帖人weicai_chen] 收藏 weicai_chen weicai_chen 等级: 结帖率:95.12% ...

  3. 转 如何在调用WCF服务之前弹出一个确认对话框

    自定义InteractiveChannelInitializer(InvocationConfirmationInteractiveChannelInitializer)定义如下.我们在BeginDi ...

  4. android穿越之旅--如何弹出一个非比寻常的窗体

    上一篇中介绍了一种闻所未闻在android执行java命令的方法,虽然这是一种非常"高级"的技术,然后并没有什么卵用,因此被移除了博客园首页.实际上也并不是一点用处也没有,对已立即 ...

  5. MySQL GROUP_CONCAT函数使用示例:如何用一个SQL查询出一个班级各个学科第N名是谁?

    如何用一个SQL查询出一个班级各个学科第N名是谁? 首先贴出建表语句,方便大家本地测试: -- 建表语句 CREATE TABLE score ( id INT NOT NULL auto_incre ...

  6. 从点击Button到弹出一个MessageBox, 背后发生了什么

    思考一个最简单的程序行为:我们的Dialog上有一个Button, 当用户用鼠标点击这个Button时, 我们弹出一个MessageBox. 这个看似简单的行为, 谁能说清楚它是如何运行起来的,背后究 ...

  7. 如何快速开发出一个高质量的APP——创业谈

    [起] 今早,一个技术群里有人想快速做出一个app,然后询问技术方案,大概是这样, 拿到了200w投资,期望花20w两个月先做出一个app,包括iOS,Android, 先,呵呵,一下, 大概预估了一 ...

  8. 给出一个数组A,找出一对 (i, j)使得A[i] <= A[j] (i < j)并且j-i最大

    题目:给出一个数组A,找出一对 (i, j)使得A[i] <= A[j] (i <= j)并且j-i最大 ,若有多个这样的位置对,返回i最小的那一对. 最直接的想法就是对于每一个 i 从数 ...

  9. windows下编辑过的文件在Linux下用vi打开行尾会多出一个^M符号

    一般情况下,windows下编辑过的文件在Linux下用vi打开行尾会多出一个^M符号,如下图: 这是因为Windows等操作系统用的文本换行符和UNIX/Linux操作系统用的不同,Windows系 ...

  10. 【M12】了解“抛出一个exception”与“传递一个参数”或“调用一个虚函数”之间的差异

    1.方法参数的声明语法和catch语句的语法是一样的,你可能会认为主调方法调用一个方法,并向其传递参数,与抛出一个异常传递到catch语句是一样的,是的,有相同之处,但也有更大的不同. 2.主调方法调 ...

随机推荐

  1. WSL终端无法启动

    WSL终端无法启动 1.状态 (1)宿主系统重新启动后,通过菜单项无法启动终端. (2)在powershell中,通过命令:wsl -l -v,查看子系统均为为stopped状态. (3)Powers ...

  2. uniapp中easycom用法详解

    Uniapp中的easycom是一种组件自动注册机制,可以让开发者更加方便地使用和管理组件.下面详细介绍下关于easycom使用方法. 什么是easycom? easycom是Uniapp框架提供的一 ...

  3. CZHA0黑客游戏

    一个自己开发的黑客游戏,里面用到了自研AC库 A0阶段: from ac import* from time import * from sys import * def printf(text): ...

  4. 《C++ STL编程轻松入门基础》溯源

    由一PDF文档(<认识 C++STL>--Vtech Electronic Ltd (SZ) VTE/TV2 terrcy tang)而来,以为不完整,寻求更完全版. 后搜索"第 ...

  5. MySQL事务还没提交,Canal就能读到消息了?

    [问题描述] 开发有天碰到一个很奇怪的问题,他的场景是这样子的: 通过Canal来订阅MySQL的binlog, 当捕获到有数据变化时,回到数据库,反查该数据的明细,然后做进一步处理. 有一次,他碰到 ...

  6. Linux配置为代理服务器,代理微信

    1.安装squid(全程使用root账号,如使用其他请注意权限问题) yum install squid 2.生成代理的账号密码 #如果没有htpasswd命令 先安装sudo yum install ...

  7. 鼎捷ERP二维码整体解决方案 Tiptop GP条码管理系统 鼎捷ERP移动解决方案 鼎捷条码扫描 鼎捷WMS仓库移动扫码 鼎捷安卓PDA扫码方案 Tiptop 出入库盘点出货条码扫码 提供源码

    本人在ERP实施公司做顾问四五年,参与企业实施ERP十多个项目,非常熟悉企业ERP流程,在实施过程遇到众多问题,提出了不少根据企业具体情况的解决方案. 最近定制开发了一套适合企业的条码扫码平台,基于鼎 ...

  8. Alchemy Nft黑客松任务(第一周)

    Alchemy是什么项目? 2019年12月,Alchemy完成1500万美元A轮融资,资方为Pantera Capital,斯坦福大学,Coinbase,三星等. 2021年4月,Alchemy以5 ...

  9. 正态分布密度函数的动画演示—R语言

    正态分布是概率统计中最重要的一种分布,其重要性我们可以从以下两方面来理解:一方面,正态分布是自然界最常见的一种分布.一般说来,若影响某一数量指标的随机因素很多,而每个因素所起的作用都不太大,则这个指标 ...

  10. mysql的concat与concat_ws拼接字符串的使用

    concat的使用 可以拼接多个字符 mysql> select concat(name,dept,job) from t1; +-----------------------+ | conca ...