POJ #1860 Currency Exchange 最短路徑算法 判斷負環
阿新 • • 發佈:2018-02-15
短路徑 pos main vector message back show 返回 .cn
Description
題目描述在這裏:鏈接
更多的樣例:鏈接
思路
我們把每種貨幣看成圖的頂點,而每個交換站點實現一對貨幣的交換,可認為增加一個交換站點就是增加兩個頂點間的一個環路。從樣例中可以知道,如果想要讓NICK的資金增加,那麽就需要存在一個權值為正的環路,使得貨幣總價值能夠無限上升。
所以現在的問題變成了如何判斷圖中是否有正環。由於貨幣交換後總價值可能降低,也就是說可能存在負權邊,那麽 Dijkstra 就不適用了,應該采用能判斷負環的 Bellman_ford ,還有它的優化算法 SPFA 。由於需要判斷圖中是否存在能使貨幣總價值無限上升的正環,那麽松弛邊的代碼也就不是原來求最短路的松弛操作了,需要變成了 dis[v] < (dis[u] - C) * R 。改了松弛操作,原本判斷負環的操作也就對應的變成了判斷正環。
AC 代碼如下:
1. BFS 判斷貨幣交換後是否增值。依據:貨幣交換相當於增加環路,那麽從 S 出發就總能回到 S,通過 S 的值來判斷其是否增值。
#include<iostream> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 105; int N, M; double V; struct Edge{View Codeint to; double R, C; }; vector<Edge> G[MAXN]; //G[i]代表從i出發的邊,vector存儲邊 void addEdge (int u, int v, double r, double c) { Edge tmp; tmp.to = v; tmp.R = r; tmp.C = c; G[u].push_back(tmp); } double dis[MAXN]; bool inQueue[MAXN]; //spfa算法判斷dis[s]是否可能大於V (實質是BFS) bool spfa (int s) {for (int i = 1; i <= N; i++) {dis[i] = 0.0; inQueue[i] = false; } dis[s] = V; queue<int> q; q.push(s); inQueue[s] = true; while (!q.empty()) { int u = q.front(); q.pop(); inQueue[u] = false; for (int j = 0; j < G[u].size(); j++) { int v = G[u][j].to; double r = G[u][j].R, c = G[u][j].C; if (dis[v] < (dis[u] - c)*r ) { dis[v] = (dis[u] - c)*r; if (!inQueue[v]) { q.push (v); inQueue[v] = true; } } } if (dis[s] > V) { return true; } } return false; } int main(void) { int S; while (cin >> N >> M >> S >> V) { for (int i = 1; i <= N; i++) G[i].clear(); for (int i = 1; i <= M; i++) { int u, v; double R1, C1, R2, C2; cin >> u >> v >> R1 >> C1 >> R2 >> C2; addEdge(u, v, R1, C1); addEdge(v, u, R2, C2); } //spfa算法判斷dis[s]是否可能大於V if (spfa(S)) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }
2.Bellman_ford 判斷是否存在正環。
#include<iostream> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 105; int N, M; double V; struct Edge{ int to; double R, C; Edge(int v, double r, double c) : to(v), R(r), C(c) {} }; vector<Edge> G[MAXN]; //G[i]代表從i出發的邊,vector存儲邊 void addEdge (int u, int v, double r, double c) { //Edge tmp; tmp.to = v; tmp.R = r; tmp.C = c; //G[u].push_back(tmp); G[u].push_back(Edge(v, r, c)); } double dis[MAXN]; bool bellman_ford (int s) { for (int i = 1; i <= N; i++) dis[i] = 0.0; dis[s] = V; bool relaxed = false; //哨兵 //最多更新N-1次dis數組 for (int i = 1; i <= N-1; i++) { relaxed = false; //遍歷M條邊 for (int u = 1; u <= N; u++) { for (int j = 0; j < G[u].size(); j++) { int v = G[u][j].to; double r = G[u][j].R, c = G[u][j].C; if (dis[v] < (dis[u] - c)*r ) { dis[v] = (dis[u] - c)*r; relaxed = true; } } } if (!relaxed) break; } //判斷是否存在正環 for (int u = 1; u <= N; u++) { for (int j = 0; j < G[u].size(); j++) { int v = G[u][j].to; double r = G[u][j].R, c = G[u][j].C; //如果還有邊可以松弛,說明存在正環 if (dis[v] < (dis[u] - c)*r ) { return false; } } } return true; //返回true說明圖不包含正環 //或者用spfa算法直接判斷dis[s]是否大於V } int main(void) { int S; while (cin >> N >> M >> S >> V) { for (int i = 1; i <= N; i++) G[i].clear(); for (int i = 1; i <= M; i++) { int u, v; double R1, C1, R2, C2; cin >> u >> v >> R1 >> C1 >> R2 >> C2; addEdge(u, v, R1, C1); addEdge(v, u, R2, C2); } //bellman_ford算法判斷是否存在正環 if (!bellman_ford(S)) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }View Code
3.SPFA 判斷是否存在正環。 SPFA算法的模板及分析在我的另一篇博客裏:鏈接
#include<iostream> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 105; int N, M; double V; struct Edge{ int to; double R, C; }; vector<Edge> G[MAXN]; //G[i]代表從i出發的邊,vector存儲邊 void addEdge (int u, int v, double r, double c) { Edge tmp; tmp.to = v; tmp.R = r; tmp.C = c; G[u].push_back(tmp); } double dis[MAXN]; bool inQueue[MAXN]; int cnt[MAXN]; //spfa判斷是否存在正環 bool spfa (int s) { memset (cnt, 0, sizeof(cnt)); memset (dis, 0.0, sizeof(dis)); memset (inQueue, false, sizeof(inQueue)); dis[s] = V; queue<int> q; q.push(s); inQueue[s] = true; while (!q.empty()) { int u = q.front(); q.pop(); inQueue[u] = false; for (int j = 0; j < G[u].size(); j++) { int v = G[u][j].to; double r = G[u][j].R, c = G[u][j].C; if (dis[v] < (dis[u] - c)*r ) { dis[v] = (dis[u] - c)*r; if (!inQueue[v]) { q.push (v); inQueue[v] = true; if (++cnt[v] > N) return false; } } } } return true; //返回true說明圖中不存在正環 } int main(void) { int S; while (cin >> N >> M >> S >> V) { for (int i = 1; i <= N; i++) G[i].clear(); for (int i = 1; i <= M; i++) { int u, v; double R1, C1, R2, C2; cin >> u >> v >> R1 >> C1 >> R2 >> C2; addEdge(u, v, R1, C1); addEdge(v, u, R2, C2); } //spfa算法判斷是否存在正環 if (!spfa(S)) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }View Code
POJ #1860 Currency Exchange 最短路徑算法 判斷負環