Holy Grail【spfa求最短路】
题目链接:https://www.jisuanke.com/contest/3004?view=challenges
题目大意:
1.一个无向图,给出六个顶点,添六条边,但是添边是有限制的。每次添边的权值要最小。
2.不能构成negative-weighted loop,negative-weighted loop指的是循环加权和为负,即从一个顶点出发在回到这个顶点的经过路径的权值和必须是 >= 0的。所以让你在u,v顶点天一条边,可以计算v - > u的最短路,然后加个负号取反。然后再加边执行下一次询问。需要进行6次SPFA。
3.dijsktra不能处理负边权,这里的边是带负的,所以用spfa,并且注意边权范围是 -1e9~1e9,所以两点之间最短路可能会超int范围,所以dis数组要开long long型。
代码如下:
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #define mem(a, b) memset(a, b, sizeof(a)) 5 #define LL long long 6 const int inf = 0x3f3f3f3f; 7 using namespace std; 8 9 int n, m; 10 int head[310], cnt, vis[310]; 11 LL dis[310]; 12 13 struct Edge 14 { 15 int to, next; 16 LL w; 17 }edge[510]; 18 19 void add(int a, int b, LL c) 20 { 21 edge[++ cnt].to = b; 22 edge[cnt].w = c; 23 edge[cnt].next = head[a]; 24 head[a] = cnt; 25 } 26 27 void spfa(int st, int ed) 28 { 29 mem(vis, 0), mem(dis, inf); 30 queue<int> Q; 31 Q.push(st); 32 dis[st] = 0; 33 vis[st] = 1; 34 while(!Q.empty()) 35 { 36 int a = Q.front(); 37 Q.pop(); 38 vis[a] = 0; 39 for(int i = head[a]; i != -1; i = edge[i].next) 40 { 41 int to = edge[i].to; 42 if(dis[to] > dis[a] + edge[i].w) 43 { 44 dis[to] = dis[a] + edge[i].w; 45 if(!vis[to]) 46 { 47 vis[to] = 1; 48 Q.push(to); 49 } 50 } 51 } 52 } 53 } 54 55 int main() 56 { 57 int T; 58 scanf("%d", &T); 59 while(T --) 60 { 61 scanf("%d%d", &n, &m); 62 cnt = 0, mem(head, -1); 63 for(int i = 1; i <= m; i ++) 64 { 65 int a, b; 66 LL c; 67 scanf("%d%d%lld", &a, &b, &c); 68 add(a, b, c); 69 } 70 for(int i = 1; i <= 6; i ++) 71 { 72 int st, ed; 73 scanf("%d%d", &st, &ed); 74 spfa(ed, st); 75 printf("%lld\n", -dis[st]); 76 add(st, ed, -dis[st]); 77 } 78 } 79 return 0; 80 }