来源:http://poj.org/problem?id=1860
题目的大意,就是要通过多次交易,使得回到开始节点时的钱数增加。
类似于寻找负权回路,但是这里要走回到开始节点。
而对于负权回路,可以用bell-manford或者SPFA,这里用了SPFA。
在SPFA时,当开始节点的钱数>原始钱数,我们就可以退出SPFA,直接输出了。
对于原始的SPFA,这里的relax操作要改成题目要求的公式。
其他的没什么可以讲了。
#include <cstdio> #include <cstring> #include <vector> #include <queue> using namespace std; const int NN=150; struct data { int v; double a, b; data() { v=a=b=0; } data(int v, double a, double b) :v(v), a(a), b(b) {} }; vector<data> e[NN]; int point, edge, beg; double ss; bool f[NN]; double ww[NN]; bool relax(int u, int v, double a, double b) { if ((ww[u]-b)*a>ww[v]) { ww[v] = (ww[u]-b)*a; return true; } return false; } bool SPFA(int beg) { queue<int> q; q.push(beg); memset(f, 0, sizeof(f)); f[beg] = true; while (!q.empty()) { int u = q.front(); for (int i=0; i<e[u].size(); i++) { int v=e[u][i].v; if (relax(u, v, e[u][i].a, e[u][i].b) && !f[v]) { if (ww[beg]>ss) return true; f[v] = true; q.push(v); } } q.pop(); f[u] = false; } return false; } int main() { scanf("%d%d%d%lf", &point, &edge, &beg, &ss); for (int i=0; i<edge; i++) { int u, v; double a,b,c,d; scanf("%d%d%lf%lf%lf%lf", &u, &v, &a, &b, &c, &d); e[u].push_back(data(v,a,b)); e[v].push_back(data(u,c,d)); } memset(ww, 0, sizeof(ww)); ww[beg] = ss; bool ff = SPFA(beg); if (ff) printf("YES\n"); else printf("NO\n"); return 0; }