题目链接:https://www.luogu.org/problem/P4568
题目大意:给定n个点,m条无向边,k次机会经过边时代价为 0 。给出起点和终点,求其最短路径。
解题思路:
两种方法,一是用拆点分层,直接跑最短路。二是dis[][]开二维数组,表示已经用了 j 次免费机会时在 i 点的最短路径。
第一种方法数组需要多开大很多倍(因为拆点),当层数以及点比较多的时候,边也就非常多,代码跑起来很慢,在这里若不用优先队列dijsktra优化会超时。
第二种方法似乎更加好,不需要将一维数组开大很多倍,只需要用二维数组记录状态,然后更新即可。跑的边也会比较的少。代码更快。
对于第一种方法。图如下:
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<algorithm> 5 #define mem(a, b) memset(a, b, sizeof(a)) 6 typedef long long ll; 7 const int MAXN = 1e6 + 100;//建了多层 点成倍增加 8 const int MAXM = 5e6 + 100; 9 const int inf = 0x3f3f3f3f; 10 using namespace std; 11 12 int n, m, k, st, ed; 13 int head[MAXN], cnt; 14 int vis[MAXN]; 15 ll dis[MAXN]; //距离开ll 稳 16 17 struct Edge 18 { 19 int to, next; 20 ll w; 21 }edge[MAXM]; 22 23 struct Node 24 { 25 int pot; 26 ll dis; 27 bool operator < (const Node &a)const 28 { 29 return dis > a.dis; 30 } 31 }node; 32 33 void add(int a, int b, ll c) 34 { 35 cnt ++; 36 edge[cnt].to = b; 37 edge[cnt].w = c; 38 edge[cnt].next = head[a]; 39 head[a] = cnt; 40 } 41 42 void dij() 43 { 44 mem(dis, inf), mem(vis, 0); 45 priority_queue<Node> Q; //记得是优先队列 46 while(!Q.empty()) Q.pop(); 47 dis[st] = 0; 48 node.pot = st, node.dis = 0; 49 Q.push(node); 50 while(!Q.empty()) 51 { 52 Node a = Q.top();//top() 53 Q.pop(); 54 if(vis[a.pot]) 55 continue; 56 vis[a.pot] = 1; 57 for(int i = head[a.pot]; i != -1; i = edge[i].next) 58 { 59 int to = edge[i].to; 60 if(vis[to]) //若该点以及确定了最短距离 则不需要再去比较了 61 continue; 62 if(dis[to] > dis[a.pot] + edge[i].w) 63 { 64 dis[to] = dis[a.pot] + edge[i].w; 65 node.pot = to, node.dis = dis[to]; 66 Q.push(node); 67 } 68 } 69 } 70 } 71 72 int main() 73 { 74 cnt = 0, mem(head, -1); 75 scanf("%d%d%d", &n, &m, &k); 76 scanf("%d%d", &st, &ed); 77 for(int i = 1; i <= m; i ++) 78 { 79 int a, b; 80 ll c; 81 scanf("%d%d%lld", &a, &b, &c); 82 add(a, b, c); 83 add(b, a, c); 84 for(int j = 1; j <= k; j ++) 85 { 86 add(a + (j - 1) * n, b + j * n, 0); //上一层往下一层建边权为 0 的边 87 add(b + (j - 1) * n, a + j * n, 0); 88 add(a + j * n, b + j * n, c); //每一层本身的边也要建 89 add(b + j * n, a + j * n, c); 90 } 91 } 92 dij(); 93 ll ans = inf; 94 for(int i = 0; i <= k; i ++) //选择到终点距离最短的那一层答案 95 ans = min(ans, dis[ed + i * n]); 96 printf("%lld\n", ans); 97 return 0; 98 }
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #define mem(a, b) memset(a, b, sizeof(a)) 5 typedef long long ll; 6 const int MAXN = 1e4 + 10; 7 const int MAXM = 5e4 + 10; 8 const int inf = 0x3f3f3f3f; 9 using namespace std; 10 11 int n, m, k, st, ed; 12 int head[MAXN], cnt, vis[MAXN][12]; 13 ll dis[MAXN][12]; 14 15 struct Edge 16 { 17 int to, next; 18 ll w; 19 }edge[2 * MAXM]; 20 21 struct Node 22 { 23 int pot, num; //点 以及 用了的机会次数 24 ll dis; 25 bool operator < (const Node &a)const 26 { 27 return dis > a.dis; 28 } 29 }node; 30 31 void add(int a, int b, ll c) 32 { 33 cnt ++; 34 edge[cnt].w = c; 35 edge[cnt].to = b; 36 edge[cnt].next = head[a]; 37 head[a] = cnt; 38 } 39 40 void dij() 41 { 42 mem(dis, inf), mem(vis, 0); 43 node.pot = st, node.dis = 0, node.num = 0; 44 dis[st][0] = 0; 45 priority_queue<Node> Q; 46 Q.push(node); 47 while(!Q.empty()) 48 { 49 Node a = Q.top(); 50 Q.pop(); 51 if(vis[a.pot][a.num]) 52 continue; 53 vis[a.pot][a.num] = 1; 54 for(int i = head[a.pot]; i != -1; i = edge[i].next) 55 { 56 int to = edge[i].to; 57 if(dis[to][a.num] > dis[a.pot][a.num] + edge[i].w) //不使用免费机会 58 { 59 dis[to][a.num] = dis[a.pot][a.num] + edge[i].w; 60 node.pot = to, node.dis = dis[to][a.num], node.num = a.num; 61 Q.push(node); 62 } 63 if(a.num == k) //如果已经把免费机会使用完了 64 continue; 65 if(dis[to][a.num + 1] > dis[a.pot][a.num]) 66 { 67 dis[to][a.num + 1] = dis[a.pot][a.num]; 68 node.pot = to, node.dis = dis[to][a.num + 1], node.num = a.num + 1; 69 Q.push(node); 70 } 71 } 72 } 73 } 74 75 int main() 76 { 77 mem(head, -1), cnt = 0; 78 scanf("%d%d%d", &n, &m, &k); 79 scanf("%d%d", &st, &ed); 80 for(int i = 1; i <= m; i ++) 81 { 82 int a, b; 83 ll c; 84 scanf("%d%d%lld", &a, &b, &c); 85 add(a, b, c); 86 add(b, a, c); 87 } 88 dij(); 89 ll ans = inf; 90 for(int i = 0; i <= k; i ++) 91 ans = min(ans, dis[ed][i]); 92 printf("%lld\n", ans); 93 return 0; 94 }