/*
题意:从1走到n,每走到一个屋子即可获得屋里的能量。
能量值可为负,问是否可以走到n
思路:
题目实际是求从起点到终点的最长路径问题
由于没到一个点,能量值不为负,所以使用d[]来记录到各点后的能量值
,初始化为0,然后使用循环进行松弛,最后判断d[n]是否大于零,如果
是则可达。但是如果图中出现正环,则可能使程序陷入死循环,则不要
在出现正环时能跳出循环。
另外,在之前需要进行一次初始化,从n开始进行逆向搜索,判断各点
是否能到达n(这一步必不可少,若在不可达的点集中出现一个环则会出错)
,然后使用队列优先的Bellman-Ford算法即可
*/
#include <cstdio>
#include <cstring>
const int nMax=110;
int G[nMax][nMax],w[nMax],d[nMax];
int q[nMax],inq[nMax],inedq[nMax];
int visit[nMax],reach[nMax];
int n;
void dfs(int u)
{
visit[u]=1;
reach[u]=1;
for(int v=1;v<=n;v++)
{
if(G[v][u] && !visit[v])
{
dfs(v);
}
}
}
int main()
{
//freopen("data.in","r",stdin);
while(scanf("%d",&n)==1)
{
if(n==-1)
break;
memset(G,0,sizeof(G));
memset(w,0,sizeof(w));
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
int k;
scanf("%d",&k);
for(int j=0;j<k;j++)
{
int u;
scanf("%d",&u);
G[i][u]=1;
}
}
memset(visit,0,sizeof(visit));
memset(reach,0,sizeof(reach));
dfs(n);
if(!reach[1])
{
printf("hopeless\n");
continue;
}
int front=0,rear=0;
memset(q,0,sizeof(q));
memset(d,0,sizeof(d));
memset(inq,0,sizeof(inq));
memset(inedq,0,sizeof(inedq));
q[front++]=1;
d[1]=100;
inq[1]=1;
inedq[1]++;
bool ok=false;
while(front!=rear)
{
int u=q[rear++];
if(rear==n)
rear=0;
inq[u]=0;
for(int v=1;v<=n;v++)
{
if(G[u][v] && reach[v] && d[u]+w[v]>d[v])
{
d[v]=d[u]+w[v];
if(!inq[v])
{
q[front++]=v;
if(front==n)
front=0;
inq[v]=1;
inedq[v]++;
if(inedq[v]>n)
{
ok=true;
break;
}
}
}
}
if(d[n]>0 || ok)
break;
}
if(d[n]>0 || ok)
printf("winnable\n");
else
printf("hopeless\n");
}
return 0;
}
10557 - XYZZY(****)---Bellman-Ford算法
最新推荐文章于 2012-07-07 23:15:48 发布