题目大意:
非常有意思的一道题,意思是有n个房间,每两个房间之间都可能存在一个有向通道,经过每个房间的时候都会消耗或增加相应的能量,房间编号是1~n,当你的能量消耗完的时候就不能继续往下走。
现在假设你的初始能力值为100,问你是否能够走到n号房间。
解题思路:
观察上面的这个图,其实我们可以发现当这个有向图不存在环形结构的时候可以直接用普通最短路的求法,但是题目要都这样就没意思了。
那么我们就来看看处理环形问题,首先负环不必要考虑,因为我们的贪心准则是越大越好,即使存在负环也不会计算下去的,那么正环结构呢?网上看了看本题的解题报告,有点坑啊,有很多我都不知道是怎么过的。
先说说简单的思路,当出现环形(必然是正环)结构的时候,我们可以直接判断这个环上的点是否与终点联通,如果联通就肯定是可以走到终点的啊,我不断的在这个正环上走,吃饱了就能走到终点了,所以关键是如何判断这个点是否与终点联通。
有看用flyod处理后用一张表保存各点之间的连通性的,这样可行,但是必然会耗时间和空间的。那么我们在想想其它思路?发现没有,我上面说只要吃饱就能走到终点,所以啊其实就是吃饱了就行了,每当一个环第一次出现的时候就把自己吃饱,也就是说保证只要联通就必然能走到终点。也就是说吃饱了也不能走到终点就是因为没有路让我走到终点。
到此整体思路讲完,你可以自己撸了!!!
我提交的最终代码:
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>
using namespace std;
const int MAXN=105;
int n;
int ep[MAXN];
int num[MAXN];
vector<int>G[MAXN];
bool spfa()
{
int d[MAXN],mark[MAXN];
int i;
for(i=1;i<=n;i++)
{
d[i]=0;
mark[i]=0;
num[i]=0;
}
d[1]=100;
queue<int> q;
q.push(1);
mark[1]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
if(num[x]==n+1)
{
continue;
}
num[x]++;
mark[x]=0;
if(num[x]==n+1)
{
d[x]=1000000;
}
for(i=0;i<G[x].size();i++)
{
int t=G[x][i];
if((d[t]<d[x]+ep[t])&&(d[x]+ep[t]>0))
{
if(t==n) return true;
d[t]=d[x]+ep[t];
if(!mark[t])
{
q.push(t);
mark[t]=1;
}
}
}
}
return false;
}
int main()
{
while(scanf("%d",&n)==1)
{
int i;
if(n==-1)
break;
if(n==1)
{
puts("winnable");
continue;
}
for(i=0;i<=n;i++)
G[i].clear();
for(i=1;i<=n;i++)
{
scanf("%d",ep+i);
int m;
scanf("%d",&m);
int j,d;
for(j=0;j<m;j++)
{
scanf("%d",&d);
G[i].push_back(d);
}
}
if(spfa())
puts("winnable");
else
puts("hopeless");
}
return 0;
}