Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3174 Accepted Submission(s): 880
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
hopeless hopeless winnable winnable
题目意思:有n个房间,每个房间都有一个能量值(可正可负)和对应的可以离开该房间的道路,离开这个房间需要在原有能量值的基础上加上该房间的能量值,当已有能量为0时游戏失败,问能否从房间1到达房间n。 起始有100个能量值。
条件:1,假设存在一个房间mid,使得1->mid->n 有正环且三者连通,那么一定可以到达第n个房间;
2,用spfa求最长路径,在不存在正环的情况下到达n的最长路径大于0说明可以到达第n个房间。
实现:先用floyd-warshall算法求传递闭包 map[ i ] [ j ] = map[ i ] [ j ] || (map[ i ][ k ] & map[ k ][ j ])。再用spfa求最长路径,在该过程中碰到正环中的点,对其判断(条件1),若成功直接跳出,反之 不在清除标记继续下一个(不让其进队列)。队列为空时,若条件1没能成立,那么说明没有正环 或者 存在的正环对1->n过程无法产生影响,我们只需判断1->n的最长路径是否大于0即可。
#include <cstdio> #include <cstring> #include <queue> #include <vector> #include <algorithm> #define MAXN 100+10 #define MAXM 10000+10 #define INF 10000000+10 using namespace std; struct Edge { int to, val, next; }edge[MAXM]; int n; int dist[MAXN], vis[MAXN], used[MAXN], head[MAXN], top; queue<int> Q; int map[MAXN][MAXN]; void init() { top = 0; memset(map, 0, sizeof(map)); for(int i = 1; i <= n; i++) { vis[i] = 0; used[i] = 0; head[i] = -1; } } void addedge(int a, int b, int d) { edge[top].to = b; edge[top].val = d; edge[top].next = head[a]; head[a] = top++; } void getmap() { int x, y, d, num; for(x = 1; x <= n; x++) { scanf("%d%d", &d, &num); while(num--) { scanf("%d", &y); addedge(x, y, d); map[x][y] = 1; } } } int floyd()//求传递闭包 { int k, i, j; for(k = 1; k <= n; k++) { for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) map[i][j] = map[i][j] || (map[i][k]&map[k][j]); } } } int judge(int mid) { if(map[1][mid] && map[mid][n]) return 1; else return 0; } int spfa()//求最长路径 判断是否存在正环 { int i, j; for(i = 1; i <= n; i++) dist[i] = 0; while(!Q.empty()) { Q.pop(); } dist[1] = 100; Q.push(1); vis[1] = 1; used[1]++; while(!Q.empty()) { int u = Q.front(); Q.pop(); if(used[u] > n)//找到正环中的点 { if(judge(u))//能通过该点到达终点 return 1; else continue; } vis[u] = 0; for(i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(dist[v] < dist[u] + edge[i].val) { dist[v] = dist[u] + edge[i].val; if(!vis[v]) { vis[v] = 1; used[v]++; Q.push(v); } } } } if(dist[n] > 0)//可以到达终点 return 1; else return 0; } int main() { while(scanf("%d", &n), n != -1) { init(); getmap(); floyd(); if(spfa()) printf("winnable\n"); else printf("hopeless\n"); } return 0; }
看了其他人的题解,思路有一点不同: 在碰到正环就跳出,遍历所有点判断(条件1)是否成立。
#include <cstdio> #include <cstring> #include <queue> #include <vector> #include <algorithm> #define MAXN 100+10 #define MAXM 10000+10 #define INF 10000000+10 using namespace std; struct Edge { int to, val, next; }edge[MAXM]; int n; int dist[MAXN], vis[MAXN], used[MAXN], head[MAXN], top; queue<int> Q; int map[MAXN][MAXN]; void init() { top = 0; memset(map, 0, sizeof(map)); for(int i = 1; i <= n; i++) { vis[i] = 0; used[i] = 0; head[i] = -1; } } void addedge(int a, int b, int d) { edge[top].to = b; edge[top].val = d; edge[top].next = head[a]; head[a] = top++; } void getmap() { int x, y, d, num; for(x = 1; x <= n; x++) { scanf("%d%d", &d, &num); while(num--) { scanf("%d", &y); addedge(x, y, d); map[x][y] = 1; } } } int floyd()//求传递闭包 { int k, i, j; for(k = 1; k <= n; k++) { for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) map[i][j] = map[i][j] || (map[i][k]&map[k][j]); } } } int judge(int mid) { if(map[1][mid] && map[mid][n]) return 1; else return 0; } int spfa()//求最长路径 判断是否存在正环 { int i, j; for(i = 1; i <= n; i++) dist[i] = 0; while(!Q.empty()) { Q.pop(); } dist[1] = 100; Q.push(1); vis[1] = 1; used[1]++; while(!Q.empty()) { int u = Q.front(); Q.pop(); vis[u] = 0; if(used[u] > n) break; for(i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(dist[v] < dist[u] + edge[i].val) { dist[v] = dist[u] + edge[i].val; if(!vis[v]) { vis[v] = 1; used[v]++; Q.push(v); } } } } if(dist[n] > 0)//可以到达终点 return 1; else { for(i = 1; i <= n; i++) { if(used[i] > n && map[1][i] && map[i][n]) return 1; } return 0; } } int main() { while(scanf("%d", &n), n != -1) { init(); getmap(); floyd(); if(spfa()) printf("winnable\n"); else printf("hopeless\n"); } return 0; }