XYZZYTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7572 Accepted Submission(s): 2162 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. 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: 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 Source |
题目大意:有从1到n个房间,每个房间都有一个能量值,
并且有连接的房间(需要处理),每进入一次这个房间,剩余
能量值就会加上这个房间的能量,初始有100点能量,问能不能
走到最后
解题思路:这可以抽象成一个有向图,边的权值可以理解为
弧尾的能量值,则显然这是一个含有负权值的图,这道题问是否
能成功,只要是有一条路可走就成功,所以需要求最长路,先用
Floyd算法扫描一遍连通性,然后再用Bellman-Ford算法求最长路
#include<stdio.h>
#include<string.h>
#define maxn 0x3f3f3f3f
struct Node{
int Start;//有向边的起始点
int End;//有向边的终点
}Edge,edge[10005];
int reach[110][110];
int energy[110];//每个房间的能量值
int dist[110];//dist函数表示初始点到i的最短距离(相当于Dijkstra函数中的D数组)
int N,edgenum;
void Floyd(){//用Floyd判断图的连通性
for(int k=1;k<=N;k++){
for(int i=1;i<=N;i++){
if(reach[i][k]){
for(int j=1;j<=N;j++){
reach[i][j]=reach[i][j]||(reach[i][k]&&reach[k][j]);
}
}
}
}
}
int bellman_ford(){
for(int i=1;i<=N;i++){
dist[i]=-maxn;//如果是找最短路,初始化成最大值
}
dist[1]=100;
for(int k=0;k<N-1;k++){
for(int i=1;i<=edgenum;i++){//对每一条边进行N-1次(N为顶点)松弛操作
if(dist[edge[i].End]<dist[edge[i].Start]+energy[edge[i].End]&&dist[edge[i].Start]+energy[edge[i].End]>0) {
dist[edge[i].End]=dist[edge[i].Start]+energy[edge[i].End];
}
}
}
if(dist[N]>0){//当到达N房间的能量为正值时赢得游戏
return 1;
}
for(int i=1;i<=edgenum;i++){//存在正环且正环上存在房间end能到达房间N
if(dist[edge[i].End]<dist[edge[i].Start]+energy[edge[i].End]&&dist[edge[i].Start]+energy[edge[i].End]>0){
if(reach[edge[i].End][N]==1)
return 1;
}
}
return 0;
}
int main(){
int conn;
while(scanf("%d",&N)!=EOF&&N!=-1){
memset(reach,0,sizeof(reach));
edgenum=1;
for(int i=1;i<=N;i++){
int m;
scanf("%d %d",&energy[i],&m);
for(int j=0;j<m;j++){
scanf("%d",&conn);
reach[i][conn]=1;
edge[edgenum].Start=i;
edge[edgenum].End=conn;
edgenum++;
}
}
Floyd();
edgenum--;//因为该算法是对边操作的,所以对边要求比较严格
if(bellman_ford()){
printf("winnable\n");
}
else{
printf("hopeless\n");
}
}
return 0;
}