http://poj.org/problem?id=1860
题意:有n种货币,m个相互兑换关系,初始拥有货币s共v元,求是否可以财富增加。
题意并不是说要走简单路径,他只是说了简单路径这个东西。
这个题暴露了对SPFA的认识不够。
首先这个SPFA是没有带优化的,玄学算法不需要优化。
一般的SPFA是节点入队次数超过n次就认为它存在负环,但是这里并不是这样判断,存在负环并不代表一定可以兑换回s(说不定在负环里只有0的汇率换回来s,导致白搞)但是这又是怎么阻止算法死循环的呢?
#include<algorithm> #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<map> #include<set> #include<stack> #include<string> #include<queue> #include<vector> using namespace std; typedef long long ll; const int MAXN = 105; const int MAXM = 1005; int top; int head[MAXN]; struct Edge { int v, nxt; double w1, w2; } edge[MAXM]; void init() { top = 0; memset(head, -1, sizeof(head)); } void add_edge(int u, int v, double w1, double w2) { ++top; edge[top].v = v; edge[top].w1 = w1; edge[top].w2 = w2; edge[top].nxt = head[u]; head[u] = top; } bool vis[MAXN]; double dis[MAXN]; queue<int>q; bool spfa(int s, int n, double val) { memset(vis, 0, sizeof(vis)); for(int i = 0; i < MAXN; ++i) dis[i] = 0; while(!q.empty()) q.pop(); q.push(s); vis[s] = 1; dis[s] = val; while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = 0; for(int i = head[u]; i != -1; i = edge[i].nxt) { int v = edge[i].v; double w1 = edge[i].w1; double w2 = edge[i].w2; if(dis[u] < w2) continue; if(dis[v] < (dis[u] - w2)*w1) { dis[v] = (dis[u] - w2) * w1; if(dis[s] > val) return 1; if(!vis[v]) { vis[v] = 1; q.push(v); } } } } return 0; } int main() { #ifdef Yinku freopen("Yinku.in", "r", stdin); #endif // Yinku int n, m, s; double v; while(~scanf("%d%d%d%lf", &n, &m, &s, &v)) { if(n == 0) break; init(); for(int i = 1; i <= m; ++i) { int u, v; scanf("%d%d", &u, &v); double w1, w2; scanf("%lf%lf", &w1, &w2); add_edge(u, v, w1, w2); scanf("%lf%lf", &w1, &w2); add_edge(v, u, w1, w2); } if(spfa(s, n, v)) puts("YES"); else puts("NO"); } }