1. 程式人生 > 其它 >Holy Grail————計蒜客

Holy Grail————計蒜客

技術標籤:演算法圖論c++

題目連結
https://nanti.jisuanke.com/t/41305/
思路
題意是給一個n個點m條有向邊的圖,題目保證可能會存在負權邊,不存在重邊和自環,也不存在負環,然後給出六條邊的起點u和終點v,題目保證在新增前不會有能從u到達v的路徑。
每次新增都要保證:第一,按照題意,是要新增一條反向邊將本來能從v到u的最短路變成權重為0(題目說花費,一個意思)。第二,新增之後不能有負環,第三,新增後的邊會影響後面的新增。所以牽扯到負環那麼本題自然採用SPFA演算法(沒用Bellman_Ford是因為第一複雜度不如SPFA,第二不習慣0.0),求出v到u的最短路後新增上負號即可。

為什麼可以直接新增負號這裡寫一下我的證明想法,可能不太規範,如果搜到最短路是正的,那麼直接在起終點新增一個負權邊不會有負環,因為是它是所有路徑的最小值且為正,那麼就算取負號也不會影響其它路徑成為負環;如果是負的同理,會找到所有路徑的最小值且為負,那麼這個負值取相反數之後就會比其它所有路徑的絕對值都要大,那麼它一定能讓所有形成的環都變成正值;如果搜不到最短路,就代表存在負環,但是題目保證了初始圖不存在負環,故這個情況不存在。
c++程式碼

#include<bits/stdc++.h>
using namespace std;

const int INF=1e9+2;
const int
N=310; int n,m; int g[N][N]; int dis[N],vis[N]; void SPFA(int u){ memset(dis, INF, sizeof(dis)); memset(vis,0,sizeof(vis)); dis[u] = 0; vis[u] = 1; queue<int> q; q.push(u); while(q.size()) { auto t=q.front(); q.pop(); vis[t]=0; for
(int i=0;i<n;i++) { if(dis[i]>dis[t]+g[t][i]) { dis[i]=dis[t]+g[t][i]; if(!vis[i]) { vis[i]=1; q.push(i); } } } } } int main() { int t; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); memset(g,INF,sizeof(g)); for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); g[a][b]=c; } for(int i=0;i<6;i++) { int u,v; scanf("%d%d",&u,&v); SPFA(v); g[u][v]=-dis[u]; printf("%d\n",g[u][v]); } } return 0; }