标签:
Description
Input
Output
Sample Input
5 0 1 2 -60 1 3 -60 1 4 20 1 5 0 0 5 0 1 2 20 1 3 -60 1 4 -60 1 5 0 0 5 0 1 2 21 1 3 -60 1 4 -60 1 5 0 0 5 0 1 2 20 2 1 3 -60 1 4 -60 1 5 0 0 -1
Sample Output
hopeless hopeless winnable winnable
综合题,看别人的代码过的。输入也太TM恶心了。有一个疑惑,为什么不用vis数组标记是否入队过也能过,那么问题来了,什么时候必须用vis数组标记??
上代码~~
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <set> 8 #include <map> 9 #include <string> 10 #include <cmath> 11 #include <stdlib.h> 12 #define N 1005 13 using namespace std; 14 15 bool dis[N][N]; 16 int n,i,j,a,b,c,d[N],cnt[N],vis[N]; 17 struct Edge{ 18 int u,v,w; 19 }; 20 vector<Edge> edge; 21 vector<int> g[N]; 22 void init() 23 { 24 for(i = 0;i<=n;i++) 25 g[i].clear(); 26 edge.clear(); 27 } 28 void add(int u,int v,int w) 29 { 30 Edge t; 31 t.u = u; t.v = v; t.w = w; 32 edge.push_back(t); 33 g[u].push_back(edge.size()-1); 34 } 35 void floyd() 36 { 37 int k; 38 for(k = 1;k<=n;k++) 39 for(i= 1;i<=n;i++) 40 for(j = 1;j<=n;j++) 41 dis[i][j] |= (dis[i][k]&&dis[k][j]); 42 } 43 int spfa() 44 { 45 queue<int> q; 46 q.push(1); 47 memset(cnt,0,sizeof(cnt)); 48 memset(d,0,sizeof(d)); 49 memset(vis,0,sizeof(vis)); 50 vis[1] = 1; 51 d[1] = 100; 52 while(!q.empty()) 53 { 54 int now = q.front(); 55 q.pop(); 56 cnt[now]++; 57 vis[now] = 0;////////// 58 if(cnt[now]>=n) return dis[now][n]; 59 for(i = 0;i<g[now].size();i++) 60 { 61 Edge e = edge[g[now][i]]; 62 if(d[e.u]+e.w>d[e.v]&&d[e.u]+e.w>0) 63 { 64 d[e.v] = d[e.u]+e.w; 65 if(vis[e.v]==0) 66 { 67 q.push(e.v); 68 vis[e.v] = 1; 69 } 70 } 71 } 72 } 73 return d[n]>0; 74 } 75 int main() 76 { 77 freopen("caicai.txt","r",stdin); 78 while(scanf("%d",&n)!=EOF) 79 { 80 if(n==-1) 81 break; 82 memset(dis,0,sizeof(dis)); 83 init(); 84 for(i = 1;i<=n;i++) 85 { 86 scanf("%d%d",&a,&b); 87 for(j = 1;j<=b;j++) 88 { 89 scanf("%d",&c); 90 add(i,c,a); 91 dis[i][c] = 1; 92 } 93 } 94 floyd(); 95 if(!dis[1][n]) 96 printf("hopeless\n"); 97 else{ 98 int ans = spfa(); 99 if(ans) 100 printf("winnable\n"); 101 else 102 printf("hopeless\n"); 103 } 104 } 105 return 0; 106 }
题解转自http://blog.csdn.net/u013445530/article/details/44066325
题意: 有n个房间(n<=100),每个房间有一个点权(第1号房间和第n号房间权值均为0),到达该房间时会自动获得该点权(可能为负权)。给出一些无 向边。有一个人,初始有能量值100,初始位置是第1号房间,要走到第n号房间,且路途中不得使身上能量值小于或等于0。能到达第n个房间就算赢,问能否 赢。
思路:
1.首先可以发现,只要知道到第n个房间时最大可以获得多少能量值(当然必须保证中途都大于0),就能知道能否赢。
2.考虑到负环情况,跑SPFA的时候最长路负环是不会去循环的,所以负环其实可以不用考虑。
3.考虑到正环情况,只要能到达正环(即SPFA处理过程中接触到正环中的点),并且正环能到达终点,就一定能赢。
4.SPFA最长路松弛操作只要把松弛条件里的大于号小于号什么的反一下就可以了。
5.由于SPFA入队的点一定是能够由源点到达的点,而如果一个点进队次数大于等于n就说明 它在环中(事实上由于最长路中负环不会循环所以这里一定是正环),那么这里只要能从该点到达终点(Floyd判断),那么就一定能赢;反之如果不能到达终 点就一定会输(因为松弛次数大于或等于n还没有结束则说明最长路不存在)。
6.点权的写法,d数组的含义是由源点s到当前点u(包含u)的路径上的点权之和,所以初始化d[s]=100.
7.SPFA中松弛要求原图的连通情况,而不能用Floyd出来的结果。
8.注意松弛条件中本题要求中途都不能<=0因此松弛优化要满足优化值>0,于是要加个d[u]+E[v]>0。
9.注意最后判断一下到达第n号房间时的能量值是否>0,这个数值即为到达第n个房间时最大可以获得多少能量值。
10.程序中map数组用来存放原图,用来SPFA中的松弛条件;reach数组用来判断u->v的连通性。
11.注意Floyd是这样写的reach[i][j]=reach[i][j] || (reach[i][k] && reach[k][j]);
12.注意输入中可到达的房间编号是以1开始的,所以程序中想从0开始编号要将输入数值减1(作死无数次……)。
标签:
原文地址:http://www.cnblogs.com/caitian/p/5886217.html