spfa+floyed+最长路+差分约束系统(F - XYZZY POJ - 1932)(题目起这么长感觉有点慌--)
题目链接: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\n"); 111 else 112 printf("winnable\n"); 113 } 114 return 0; 115 } 116