找工作

【问题描述】

  奶牛们没钱了,正在找工作。FJ知道后,希望奶牛们四处转转,碰碰运气。而且他还加了一条要求:一头奶牛在一个城市最多只能赚D(0 < D <= 1000)美圆,然后他必须到另一个城市工作。当然,他可以在别处工作一阵后又回来再多赚D美圆。而且这样往往返返的次数没有限制。

  城市间P(1<=P<=150)条单向道路连接,共有N(2<=N<=300)座城市(编号为1..N)。贝西当前在城市S。道路i从城市Ai到城市Bi,在道路上行走不用花费任何费用。

  为了帮助贝西,FJ让他使用他的私人飞机,飞机有F(1<=F<=350)条航线,第j条航线是从城市Aj到城市Bj,费用是Tj(1<=Tj<=50000)美圆,如果贝西手中没有现钱,可以用以后赚的钱来付机票钱,贝西可以选择任何时候,任何城市退休。

  如果在工作时间上不作限制,贝西总共可以赚多少钱呢?如果赚的钱不会出现限制,就输出INF。

【输入格式】

  第1行:5个空格分开的整数D,P,N,F,S
  第2到第P+1行:第i+1行包含2个空格分开的整数,表示从Ai到Bi的单向道路。
  第P+2到P+F+1行:第P+j包括3个空格分开的整数,表示一条从Aj到Bj的单向航线,费用为Tj

【输出格式】

  在上述规则下得最多可赚得钱数。

【输入样例】

【样例1】
100 3 5 2 1
1 5
2 3
1 4
5 2 150
2 5 120

【样例2】
100 3 5 2 1
1 5
2 3
1 4
5 2 70
2 5 120

【输出样例】

【样例1】
250

【样例2】
INF

【数据范围】

N<=300

这道题要用一种重要的思想,就是把一个点拆成2个点(i和i+n),这样就可以把点权换成边权,然后直接进行spfa就可以了。
另一种怪异方法

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
using namespace std;
const int maxn=605;
const int inf=200000000;
vector<int>g[maxn],w[maxn];
int D,p,n,f,s,d[maxn],vis[maxn]={0},qn[maxn]={0},ok=0;

void init()
{
    scanf("%d%d%d%d%d",&D,&p,&n,&f,&s);
    for(int i=1;i<=n;i++)
    {
        g[i].push_back(i+n);//拆点。
        w[i].push_back(D);
    }
    for(int i=1;i<=p;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        g[x+n].push_back(y);//i进,i+n出。
        w[x+n].push_back(0);
    }
    for(int i=1;i<=f;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        g[x+n].push_back(y);
        w[x+n].push_back(-z);
    }
    for(int i=1;i<=2*n;i++)
    d[i]=-inf;
}

void spfa()
{
    queue<int>q;
    q.push(s);
    d[s]=0;
    vis[s]=1;
    qn[s]++;
    while(!q.empty())
    {
        int i=q.front();
        q.pop();
        vis[i]=0;
        for(int k=0;k<g[i].size();k++)
        {
            int j=g[i][k],c=w[i][k];
            if(d[i]+c<=d[j]) continue;
            d[j]=d[i]+c;
            if(vis[j]) continue;
            vis[j]=1;
            qn[j]++;
            if(qn[j]>n)
            {
                ok=1;
                return;
            }
            q.push(j);
        }
    }
}
int main()
{
    init();
    spfa();
    if(ok)
    printf("INF");
    else 
    {
        int ans=0;
        for(int i=1;i<=2*n;i++)
           ans=max(ans,d[i]);
        printf("%d",ans);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值