spfa+floyed+最长路+差分约束系统(F

题目链接:https://cn.vjudge.net/contest/276233#problem/F

题目大意:给你n个房子能到达的地方,然后每进入一个房子,会消耗一定的生命值(有可能是负),问你一开始在第一个方间,初始生命值是100,最终能不能从第n个房间走出?

具体思路:首先,我们需要建图,按照正常的建立就可以了,然后再去跑一个spfa,注意这个spfa求的是最长路,然后判断一下,在没有正环的时候,看一下最终到达的n是不是正的,如果是正的,那么肯定行,否则的话,再去判断有没有正环,如果有正环,并且能够到达n点,这也是符合的情况。然后对于正环的判断,如果有正环,我们无法判断是否能到达第n个点,这个时候就需要用到floyed了,我们通过floyed判断第一个点能不能到达最后一个点,然后再判断一下中转点是不是一个正环上的点,这样的话,我们可以先通过正环加上无限的生命值,然后出去就可以了,这样又不会死。。。

一点小感悟,如果是判断正环还是负环,我们都可以通过spfa进行判断,判断条件就是判断这个点入队列的次数和总的点数,如果一个点入队列的次数大于总的点数,那么就可以判断是正环还是负环了,但是一个spfa只能判断一种,因为用spfa判断的时候,最长路和最短路的松弛条件是不一样的,所以需要判断的话得分开判断。

 AC代码:

  1 #include<bit/stdc++.h>
  9 using namespace std;
 10 # define ll long long
 11 # define inf 0x3f3f3f3f
 12 const int maxn = 200+100;
 13 int Map[maxn][maxn];
 14 int head[maxn],vis[maxn],dis[maxn],out[maxn];
 15 struct node
 16 {
 17     int to;
 18     int cost;
 19     int nex;
 20 } edge[maxn*maxn];
 21 int n,num;
 22 void addedge(int fr,int to,int cost)
 23 {
 24     edge[num].to=to;
 25     edge[num].cost=cost;
 26     edge[num].nex=head[fr];
 27     head[fr]=num++;
 28 }
 29 void init()
 30 {
 31     memset(Map,0,sizeof(Map));
 32     for(int i=0; i<maxn; i++)
 33     {
 34        Map[i][i]=1;
 35         out[i]=0;
 36         head[i]=-1;
 37         vis[i]=0;
 38         dis[i]=-inf;
 39     }
 40     num=0;
 41 }
 42 int spfa(int st)
 43 {
 44     dis[st]=100;
 45     vis[st]=1;
 46     queue<int>q;
 47     q.push(1);
 48     while(!q.empty())
 49     {
 50         int tmp=q.front();
 51         q.pop();
 52         if(++out[tmp]>n)
 53             break;
 54         vis[tmp]=0;
 55         for(int i=head[tmp]; i!=-1; i=edge[i].nex)
 56         {
 57             int u=edge[i].to;
 58             if(dis[u]<dis[tmp]+edge[i].cost&&dis[tmp]+edge[i].cost>0)
 59             {
 60                 dis[u]=dis[tmp]+edge[i].cost;
 61                 if(vis[u])
 62                     continue;
 63                 vis[u]=1;
 64                 q.push(u);
 65             }
 66         }
 67     }
 68     if(dis[n]>0)
 69         return 1;
 70     for(int i=1; i<=n; i++)  {
 72         for(int j=1; j<=n; j++) {
 74             for(int k=1; k<=n; k++) {
 76                 if(Map[j][i]&&Map[i][k]){
 78                     Map[j][k]=1;
 79                 }
 80             }
 81         }
 82     }
 83     for(int i=1; i<=n; i++) {
 85         if(Map[1][i]&&Map[i][n]&&out[i]>n)
 86             return 1;
 87     }
 88     return 0;
 89 }
 90 int main()
 91 {
 92     while(~scanf("%d",&n)){
 94         if(n==-1)break;
 95         init();
 96         int t,ed;
 97         for(int i=1; i<=n; i++)
 98         {
 99             int cost,ti;
100             scanf("%d %d",&cost,&ti);
101             while(ti--)
102             {
103                 scanf("%d",&ed);
104                 addedge(i,ed,cost);
105                 Map[i][ed]=1;
106             }
107         }
108         int ans=spfa(1);
109         if(ans==0)
110             printf("hopeless
");
111         else
112             printf("winnable
");
113     }
114     return 0;
115 }
116  
原文地址:https://www.cnblogs.com/letlifestop/p/10262767.html