XYZZY(spfa || dfs)
阿新 • • 發佈:2018-12-14
題意:有N個房間,剛開始你位於1號房間,有100的能量值,你要到達N號房間,每兩個房間之間有單向門相連線,你到達某個房間可以加上該房間的能量值,如果你在未到達N號房間之前能量值耗盡,則死亡,否則勝利。
spfa思路:通過不斷地進行鬆弛操作,使得存在迴路的點對應的能量值不斷變大變大,或者是能量不斷變大的次數超過一個給定的值(這個值要很大很大,我設定的是10000),到達終點能量依然大於0為止。到不了終點或者到終點能量值耗盡,則死亡,否則勝利。
AC程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e3; #define inf 0x3f3f3f3f int n,m; int d[maxn],vis[maxn],cnt[maxn]; vector<pair<int,int> >E[maxn]; void init() { for(int i = 0; i < maxn; i++) vis[i] = 0, cnt[i] = 0; for(int i = 0; i < maxn; i++) d[i] = 0; for(int i = 0; i < maxn; i++) E[i].clear(); } void spfa() { d[1] = 100; vis[1] = 1; queue <int> Q; Q.push(1); while(!Q.empty()) { int now = Q.front(); Q.pop(); vis[now] = 0; for(int j = 0; j < E[now].size(); j++) { int v = E[now][j].first; if(d[v] < d[now] + E[now][j].second && cnt[v] < 10000) { cnt[v]++; d[v] = d[now] + E[now][j].second; if(vis[v]) continue; vis[v] = 1; Q.push(v); } } } } int main() { int n; while(~scanf("%d",&n)) { if(n == -1) break; init(); int a,b,x; for(int i = 1; i <= n; i++) { scanf("%d%d",&x,&m); for(int j = 1; j <= m; j++) { scanf("%d",&b); E[i].push_back(make_pair(b,x)); } } spfa(); if(d[n] > 0) puts("winnable"); else puts("hopeless"); } return 0; }
dfs思路:當發現有個和為正值的環存在時,直接求看該點能否直接到達終點。如果可以,直接返回true,即勝利。否則,繼續搜尋,當發現所有路徑都不能到達終點時,返回false。雖然能ac但不正確。
判斷正環的地方 d[u]+e[v]>d[v] 只是點u存在到點v的邊,從點u到點v會使點v的值增大,但是點v不一定存在路徑能回到點u,這個不一定是一個環。 一組很簡單的資料 7 0 2 2 4 -10 1 3 -10 1 6 -10 1 5 30 1 3 -200 1 7
0 0 應該輸出失敗但是輸出了成功 就是在點5到點3過程中,可以使點3的值增大,就判定點5和點3之間有正環,然後從點3找到了到終點7的通路,就判為成功,其實點5和點3之間沒有正環,整個圖都沒有環。
AC程式碼:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e3; #define inf 0x3f3f3f3f int n,m; int d[maxn],vis[maxn], energy[maxn]; vector<int >E[maxn]; void init() { for(int i = 0; i < maxn; i++) d[i] = 0, energy[i] = 0; for(int i = 0; i < maxn; i++) E[i].clear(); } int dfs(int u) { if(u == n) return 1; vis[u] = 1; for(int i = 0; i < E[u].size(); i++) { int v = E[u][i]; if(!vis[v]) { if(dfs(v)) return 1; } } return 0; } int DFS(int u, int e) { if(u == n) return 1; d[u] = energy[u] + e; for(int i = 0; i < E[u].size(); i++) { int v = E[u][i]; if(d[u] + energy[v] > 0) { if(!d[v]) { if(DFS(v, d[u])) return 1; } else if(d[v] < d[u] + energy[v]) { memset(vis,0,sizeof(vis)); if(dfs(v)) return 1; } } } return 0; } int main() { int m,k; while(~scanf("%d",&n) && n != -1) { init(); for(int i = 1; i <= n; i++) { scanf("%d%d",&energy[i],&m); for(int j = 1; j <= m; j++) { scanf("%d",&k); E[i].push_back(k); } } if(DFS(1,100)) puts("winnable"); else puts("hopeless"); } return 0; }