POJ 3259 Wormholes【最短路/SPFA判断负环模板】
農(nóng)夫約翰在探索他的許多農(nóng)場(chǎng),發(fā)現(xiàn)了一些驚人的蟲(chóng)洞。蟲(chóng)洞是很奇特的,因?yàn)樗且粋€(gè)單向通道,可讓你進(jìn)入蟲(chóng)洞的前達(dá)到目的地!他的N(1≤N≤500)個(gè)農(nóng)場(chǎng)被編號(hào)為1..N,之間有M(1≤M≤2500)條路徑,W(1≤W≤200)個(gè)蟲(chóng)洞。FJ作為一個(gè)狂熱的時(shí)間旅行的愛(ài)好者,他要做到以下幾點(diǎn):開(kāi)始在一個(gè)區(qū)域,通過(guò)一些路徑和蟲(chóng)洞旅行,他要回到最開(kāi)時(shí)出發(fā)的那個(gè)區(qū)域出發(fā)前的時(shí)間。也許他就能遇到自己了:)。為了幫助FJ找出這是否是可以或不可以,他會(huì)為你提供F個(gè)農(nóng)場(chǎng)的完整的映射到(1≤F≤5)。所有的路徑所花時(shí)間都不大于10000秒,所有的蟲(chóng)洞都不大于萬(wàn)秒的時(shí)間回溯。Input第1行:一個(gè)整數(shù)F表示接下來(lái)會(huì)有F個(gè)農(nóng)場(chǎng)說(shuō)明。 每個(gè)農(nóng)場(chǎng)第一行:分別是三個(gè)空格隔開(kāi)的整數(shù):N,M和W 第2行到M+1行:三個(gè)空格分開(kāi)的數(shù)字(S,E,T)描述,分別為:需要T秒走過(guò)S和E之間的雙向路徑。兩個(gè)區(qū)域可能由一個(gè)以上的路徑來(lái)連接。 第M +2到M+ W+1行:三個(gè)空格分開(kāi)的數(shù)字(S,E,T)描述蟲(chóng)洞,描述單向路徑,S到E且回溯T秒。OutputF行,每行代表一個(gè)農(nóng)場(chǎng) 每個(gè)農(nóng)場(chǎng)單獨(dú)的一行,” YES”表示能滿足要求,”NO”表示不能滿足要求。Sample Input
2 3 3 1 1 2 2 1 3 4 2 3 1 3 1 3 3 2 1 1 2 3 2 3 4 3 1 8Sample Output
NO YESHint
For farm 1, FJ cannot travel back in time.?For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.
?
#include<cstdio> #include<string> #include<cstdlib> #include<cmath> #include<iostream> #include<cstring> #include<set> #include<queue> #include<algorithm> #include<vector> #include<map> #include<cctype> #include<stack> #include<sstream> #include<list> #include<assert.h> #include<bitset> #include<numeric> #define debug() puts("++++") #define gcd(a,b) __gcd(a,b) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define fi first #define se second #define pb push_back #define sqr(x) ((x)*(x)) #define ms(a,b) memset(a,b,sizeof(a)) #define sz size() #define be begin() #define mp make_pair #define pu push_up #define pd push_down #define cl clear() #define lowbit(x) -x&x #define all 1,n,1 #define rep(i,x,n) for(int i=(x); i<=(n); i++) #define in freopen("in.in","r",stdin) #define out freopen("out.out","w",stdout) using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int,int> P; const int INF = 0x3f3f3f3f; const LL LNF = 1e18; const int maxn = 1e5+20; const int maxm = 1e6 + 10; const double PI = acos(-1.0); const double eps = 1e-8; const int dx[] = {-1,1,0,0,1,1,-1,-1}; const int dy[] = {0,0,1,-1,1,-1,1,-1}; int dir[4][2] = {{0,1},{0,-1},{-1,0},{1,0}}; const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; int tot,n,m,x,s; int u,v,w; int dis[maxn]; int cnt[maxn],vis[maxn]; struct cmp {bool operator()(int a,int b){return dis[a] > dis[b];} };int head[maxn]; struct node {int v,w,nxt; }e[maxn]; void init() {tot=0;ms(cnt,0);ms(head,-1);ms(dis,INF);//求最長(zhǎng)路徑開(kāi)始設(shè)為0ms(vis,0); } void add(int u,int v,int w) {e[tot].v=v;e[tot].w=w;e[tot].nxt=head[u];head[u]=tot++; }int spfa(int s) {queue<int> q;vis[s]=1;dis[s]=0;cnt[s]++;q.push(s);while(!q.empty()){int u = q.front(); q.pop();vis[u]=0; // for(int i=head[u];i!=-1;i=e[i].nxt){int v = e[i].v;if(dis[v] > dis[u] + e[i].w){dis[v] = dis[u] + e[i].w;if(!vis[v]){vis[v]=1;q.push(v);if(++cnt[v]>n) return 1;//有負(fù)環(huán) }}}}return 0; }int main() {int t;scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&m,&w);init();int a,b,c;for(int i=1;i<=m;i++){scanf("%d%d%d",&a,&b,&c);add(a,b,c);add(b,a,c);}for(int i=1;i<=w;i++){scanf("%d%d%d",&a,&b,&c);add(a,b,-c);}if(spfa(1)) puts("YES");else puts("NO");} } /* 【題意】【類型】 SPFA判斷負(fù)環(huán)【分析】 spfa算法我們都知道spfa算法是對(duì)bellman算法的優(yōu)化,那么如何用spfa算法來(lái)判斷負(fù)權(quán)回路呢?我們考慮一個(gè)節(jié)點(diǎn)入隊(duì)的條件是什么,只有那些在前一遍松弛中改變了距離估計(jì)值的點(diǎn),才可能引起他們的鄰接點(diǎn)的距離估計(jì)值的改變。因此,用一個(gè)先進(jìn)先出的隊(duì)列來(lái)存放被成功松弛的頂點(diǎn)。同樣,我們有這樣的定理:“兩點(diǎn)間如果有最短路,那么每個(gè)結(jié)點(diǎn)最多經(jīng)過(guò)一次。也就是說(shuō),這條路不超過(guò)n-1條邊。”(如果一個(gè)結(jié)點(diǎn)經(jīng)過(guò)了兩次,那么我們走了一個(gè)圈。如果這個(gè)圈的權(quán)為正,顯然不劃算;如果是負(fù)圈,那么最短路不存在;如果是零圈,去掉不影響最優(yōu)值)。也就是說(shuō),每個(gè)點(diǎn)最多入隊(duì)n-1次(這里比較難理解,需要仔細(xì)體會(huì),n-1只是一種最壞情況,實(shí)際中,這樣會(huì)很大程度上影響程序的效率)。有了上面的基礎(chǔ),思路就很顯然了,加開(kāi)一個(gè)數(shù)組記錄每個(gè)點(diǎn)入隊(duì)的次數(shù)(num),然后,判斷當(dāng)前入隊(duì)的點(diǎn)的入隊(duì)次數(shù),如果大于n-1,則說(shuō)明存在負(fù)權(quán)回路。【時(shí)間復(fù)雜度&&優(yōu)化】【trick】【數(shù)據(jù)】 */ View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/Roni-i/p/9446542.html
總結(jié)
以上是生活随笔為你收集整理的POJ 3259 Wormholes【最短路/SPFA判断负环模板】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2018.7月Vue优质开源项目清单
- 下一篇: leetcode-44. Wildcar