BZOJ 2019 [Usaco2009 Nov]找工作:spfa【最长路】【判正环】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2019

题意:

  奶牛们没钱了,正在找工作。农夫约翰知道后,希望奶牛们四处转转,碰碰运气。

  而且他还加了一条要求:一头牛在一个城市最多只能赚D(1 <= D <= 1,000)美元,然后它必须到另一座城市工作。当然,它可以在别处工作一阵后又回来原来的城市再最多赚D美元。而且这样往往返返的次数没有限制。

  城市间有P (1 <= P <= 150)条单向路径连接,共有N(2 <= N <= 220)座城市,编号1..N. 贝希当前处在城市S (1 <= S <= N)。路径 i 从城市A[i]到城市B[i](1 <= A[i] <= N, 1 <= B[i] <= N),在路径上行走不用花任何费用。

  为了帮助贝希,约翰让它使用他的私人飞机服务。这项服务有F条(1 <= F <= 350)航线,每条航线是从城市J[i]飞到另一座城市K[i](1 <=J[i] <= N, 1 <= K[i] <= N),费用是T[i] (1 <= T[i] <= 50,000)美元。

  如果贝希手中如果没有现钱,可以用以后赚的钱来付机票钱。

  贝希可以选择任何时候,在任何城市退休。

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

 

题解:

  spfa找最长路。

  如果有点入队超过n次,则存在正环,return -1。

  建边:

    (1)对于城市间的道路,边权设为D。

    (2)对于航线,边权设为D - T[i]。

 

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <vector>
  5 #include <queue>
  6 #define MAX_N 250
  7 
  8 using namespace std;
  9 
 10 struct Edge
 11 {
 12     int dest;
 13     int len;
 14     Edge(int _dest,int _len)
 15     {
 16         dest=_dest;
 17         len=_len;
 18     }
 19     Edge(){}
 20 };
 21 
 22 int n,p,f,d,s;
 23 int ans;
 24 int dis[MAX_N];
 25 int cnt[MAX_N];
 26 bool vis[MAX_N];
 27 vector<Edge> edge[MAX_N];
 28 queue<int> q;
 29 
 30 void read()
 31 {
 32     cin>>d>>p>>n>>f>>s;
 33     int a,b,c;
 34     for(int i=0;i<p;i++)
 35     {
 36         cin>>a>>b;
 37         edge[a].push_back(Edge(b,d));
 38     }
 39     for(int i=0;i<f;i++)
 40     {
 41         cin>>a>>b>>c;
 42         edge[a].push_back(Edge(b,d-c));
 43     }
 44 }
 45 
 46 int get_front()
 47 {
 48     int now=q.front();
 49     q.pop();
 50     vis[now]=false;
 51     return now;
 52 }
 53 
 54 void insert(int now)
 55 {
 56     if(vis[now]) return;
 57     q.push(now);
 58     vis[now]=false;
 59     cnt[now]++;
 60 }
 61 
 62 int spfa(int start)
 63 {
 64     memset(dis,0x80,sizeof(dis));
 65     memset(cnt,0,sizeof(cnt));
 66     memset(vis,false,sizeof(vis));
 67     insert(start);
 68     dis[start]=d;
 69     int res=d;
 70     while(!q.empty())
 71     {
 72         int now=get_front();
 73         for(int i=0;i<edge[now].size();i++)
 74         {
 75             Edge temp=edge[now][i];
 76             if(dis[temp.dest]<dis[now]+temp.len)
 77             {
 78                 dis[temp.dest]=dis[now]+temp.len;
 79                 insert(temp.dest);
 80                 if(cnt[temp.dest]>n) return -1;
 81                 res=max(res,dis[temp.dest]);
 82             }
 83         }
 84     }
 85     return res;
 86 }
 87 
 88 void solve()
 89 {
 90     ans=spfa(s);
 91 }
 92 
 93 void print()
 94 {
 95     cout<<ans<<endl;
 96 }
 97 
 98 int main()
 99 {
100     read();
101     solve();
102     print();
103 }

 

转载于:https://www.cnblogs.com/Leohh/p/7635994.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值