POJ-1860 Currency Exchange bellman

该题是给定某一货币,然后再给定一些兑换的条件,问能否使得钱币总数增加,是不是非常诱人呢?

对该题的一个转化就是如果在转化的过程中出现了环的话,那么我们就可以在这个环内不停的进行转化,以致钱币数量无穷大,再反过来兑换就可以得到原始的币种了,而且一定会增加。

利用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"); } }
posted @ 2012-06-30 16:43  沐阳  阅读(235)  评论(0编辑  收藏  举报