NYOJ-183赚钱啦,bellman//spfa水过,,题还是蛮变态的赶脚~~

赚钱啦

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 5
描述

某国家里有N个城市,分别编号为0~N-1,一个精明的商人准备从0号城市旅行到N-1号城市,在旅行的过程中,从一个城市移动到另外一个城市需要有一定的花费,并且从A城市移动到B城市的花费和B城市移动到A城市的花费相同,但是,从A城市移动到B城市能赚取的钱和从B城市移动到A城市赚的钱不一定相同。

现在,已知各个城市之间移动的花费和城市之间交易可赚取的金钱,求该商人在从0号城市移动到N-1号城市的过程中最多能赚取多少钱?

输入
第一行是一个整数T(T<=10)表示测试数据的组数
每组测试数据的第一行是两个整数N,M表示,共有N个城市(1<N<=1000),M条路(1<=M<=1000)
随后的M行,每行有5个正整数,前两个数a,b(0<=a,b<N)表示两个城市的编号。后面的三个数c,u,v分别表示在a,b城市之间移动的花费,a城市移动到b城市可赚取的资金,b城市移动到a城市可赚取的资金。
(0<=c,u,v<=1000)
输出
如果商人能够在旅行过程中赚取无限多的资金,则输出$$$
否则输出他在移动过程中最多能赚取的资金数量
如果只会赔钱的话就输出一个负数,表示最少赔的钱数。
样例输入
2
2 1
0 1 10 11 11
3 3
0 1 10 16 0
1 2 10 15 5
0 2 20 32 0
样例输出
$$$
12
来源
2011年ACM队队长选拨赛

   与最短路不同的是这道题在题意上有很大的变更,求的是能获取最大资金,但方法可以用Spfa,或者bellman算法,只不过在存双向图的时候要特别注意,这里介绍一下bellman算法,代码还是挺简洁的;可以用邻接矩阵储存权值,就是在利用bellman算法的时候再反向判断一下另一个顶点就可以了,具体看代码:有不足之处望多多指教,谢谢:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=-0x3f3f3f3f;//注意;
const int N=1000+10;
struct node
{
    int u,v,c,a,b;
} a[N];
int d[N];
int spfa(int n,int m)
{
    for(int i=0; i<n; i++)
        d[i]=i==0?0:INF;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
        {
            if(d[a[j].v]<d[a[j].u]+a[j].a)//判断终点(两点中被指向的那个)
            {
                d[a[j].v]=d[a[j].u]+a[j].a;
                if(i>=n-1)//存在正环图;
                    return 1;
            }
            if(d[a[j].u]<d[a[j].v]+a[j].b)//判断起点;
            {
                d[a[j].u]=d[a[j].v]+a[j].b;
                if(i>=n-1)
                    return 1;
            }
        }
    return 0;
}
int main()
{
    int t,n,m,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        int f=0;
        for(i=0; i<m; i++)
        {
            scanf("%d%d%d%d%d",&a[i].u,&a[i].v,&a[i].c,&a[i].a,&a[i].b);
            a[i].a-=a[i].c,a[i].b-=a[i].c;
            if(a[i].a+a[i].b>0)
                f=1;
        }
        if(f)
            printf("$$$\n");
        else
        {
            int k=spfa(n,m);
            if(k)
                printf("$$$\n");
            else
                printf("%d\n",d[n-1]);
        }
    }
    return 0;
}
自我感觉代码比较简短,易懂,有的地方还可以改进优化;


你可能感兴趣的:(NYOJ-183赚钱啦,bellman//spfa水过,,题还是蛮变态的赶脚~~)