该题是给定某一货币,然后再给定一些兑换的条件,问能否使得钱币总数增加,是不是非常诱人呢?
对该题的一个转化就是如果在转化的过程中出现了环的话,那么我们就可以在这个环内不停的进行转化,以致钱币数量无穷大,再反过来兑换就可以得到原始的币种了,而且一定会增加。
利用bellman算法能过得到是否存在环,由于最长的环的路径长度是N-1(N各节点)所以我们只要对所有的边进行N-1次松弛,然后再看是否还可以继续松弛来判断是否有环的形成。
代码如下:
#include <cstdlib> #include <cstring> #include <cstdio> #define MAXN 205 using namespace std; int N, M, S, cnt; double V, dis[MAXN]; struct edge { int a, b; double r, c; }e[MAXN]; bool bellman() { memset(dis, 0, sizeof (dis)); memset(hash, 0, sizeof (hash)); dis[S] = V; hash[S] = 1; for (int j = 1; j <= N-1; ++j) { for (int i = 1; i <= cnt; ++i) { // 遍历所有的边 if ((dis[ e[i].a ]-e[i].c)*e[i].r - dis[ e[i].b ] > 1e-6) { dis[ e[i].b ]= (dis[ e[i].a ]-e[i].c)*e[i].r;
// 不能够在此处进行visit判断是否成环,因为可能在一次更新中更新两次 } } } for (int i = 1; i <= cnt; ++i) { if ((dis[ e[i].a ]-e[i].c)*e[i].r - dis[ e[i].b ] > 1e-6) { return 1; } } return 0; } int main() { int a, b; double rab, cab, rba, cba; while (scanf("%d %d %d %lf", &N, &M, &S, &V) == 4) { cnt = 0; for (int i = 0; i < M; ++i) { scanf("%d %d %lf %lf %lf %lf", &a, &b, &rab, &cab, &rba, &cba); ++cnt; e[cnt].a = a, e[cnt].b = b, e[cnt].r = rab, e[cnt].c = cab; ++cnt; e[cnt].a = b, e[cnt].b = a, e[cnt].r = rba, e[cnt].c = cba; } printf(bellman()? "YES\n":"NO\n"); } }