XYZZY
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 5804 Accepted Submission(s):
1681
Problem Description
It has recently been discovered how to run open-source software on the Y-Crate gaming device. A number of enterprising designers have developed Advent-style games for deployment on the Y-Crate. Your job is to test a number of these designs to see which are winnable.
Each game consists of a
set of up to 100 rooms. One of the rooms is the start and one of the rooms is
the finish. Each room has an energy value between -100 and +100. One-way
doorways interconnect pairs of rooms.
The player begins in the start
room with 100 energy points. She may pass through any doorway that connects the
room she is in to another room, thus entering the other room. The energy value
of this room is added to the player‘s energy. This process continues until she
wins by entering the finish room or dies by running out of energy (or quits in
frustration). During her adventure the player may enter the same room several
times, receiving its energy each time.
Input
The input consists of several test cases. Each test case begins with n, the number of rooms. The rooms are numbered from 1 (the start room) to n (the finish room). Input for the n rooms follows. The input for each room consists of one or more lines containing:
the energy value for
room i
the number of doorways leaving room i
a list of the rooms that
are reachable by the doorways leaving room i
The start and finish rooms will
always have enery level 0. A line containing -1 follows the last test case.
Output
In one line for each case, output "winnable" if it is
possible for the player to win, otherwise output "hopeless".
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
这是一道神奇的图论题,因为每间房间都有自己所带的能量数,所以显而易见的:如果存在环路而且走完一圈之后能量是增长的,并且这个环和终点之间有路径联通,就可以判断一定能走到终点。不然就只能老老实实spfa看看终点的权值是否大于0;
相对来说简单一点,但有几个坑点需要注意:
1、判环的时候如果有正环,不能立刻退出,还要判断一下和终点是否联通,若不连通是没有意义的。
2、因为这道题的权值在点上,所以spfa是要修改一下条件。
3、数据范围,Floyd的复杂度是o(n^3),幸好这道题节点数不超过一百。先用floyd改一下判断节点连通情况,再spfa判正环。
#include<iostream> #include<cstdio> #include<vector> #include<set> #include<map> #include<string.h> #include<algorithm> #include<queue> #define inf 0x3f3f3f3f using namespace std; int ma[105][105]; int reach[105][105]; int power[105]; int flod(int n) { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) if(reach[i][j]||(reach[i][k]&&reach[k][j])) reach[i][j]=1; if(reach[1][n]) return 1; return 0; } int spfa(int n) { queue<int> run; // int vis[105]={0}; int cnt[105]={0}; int quan[105]; memset(quan,0,sizeof(quan)); run.push(1); //vis[1]=1; cnt[1]++; quan[1]=100; while(!run.empty()) { int cur=run.front(); run.pop(); if(++cnt[cur]>=n) { if(reach[cur][n]) return 1; else break; } for(int i=1;i<=n;i++) if(ma[cur][i]&&quan[i]<quan[cur]+power[i]&&quan[cur]+power[i]>0) { quan[i]=quan[cur]+power[i]; run.push(i); } } if(quan[n]>0) return 1; return 0; } int main() { int n; while(~scanf("%d",&n)) { if(n==-1) break; memset(ma,0,sizeof(ma)); memset(reach,0,sizeof(reach)); memset(power,0,sizeof(power)); for(int i=1;i<=n;i++) { int k; scanf("%d%d",&power[i],&k); for(int j=1;j<=k;j++) { int tem; scanf("%d",&tem); ma[i][tem]=1; reach[i][tem]=1; } } if(!flod(n)) { printf("hopeless\n"); continue; } if(!spfa(n)) printf("hopeless\n"); else printf("winnable\n"); } return 0; }