UVA_10557

这个题目实际上是求一个从起点到终点的最长路。

但是由于路过每个点时权值都不能为负,所以我们在初始化距离数组d[]时要初始化0。之后就是用队列优化的Bellman-Ford算法去求最长路了,但是还有一些细节需要注意。

我们当然可以在用这个算法时选择d[n]>0是就跳出循环来减少计算量,但也会找到使这个算法崩溃的例子,比如在某个位置存在一个正圈,而由这个正圈却不能到达终点,那么程序就会一直跑下去。但同样的,我们也不能见圈就跳,因为毕竟还是有些正圈可以到达终点的。这便要求我们去判断哪些正圈可以到达终点。

于是我们可以选择在找最长路之前先做一下预处理,把所有能够到达终点的点找出来,一个比较好的办法就是从终点开始逆向深搜,然后依次标记搜到的点即可,如果最后起点没有被标记,那就直接输出hopeless就可以了。

后面在使用队列优化的Bellman-Ford算法时,我们在判断条件上多加一个是否可达终点的判断即可,如果该点可达终点我们再进行求最长路的操作。

#include<stdio.h>
#include
<string.h>
int G[110][110],w[110],d[110],n;
int q[110],inq[110],inedq[110];
int vis[110],reach[110];
void dfs(int v)
{
int u;
for(u=1;u<=n;u++)
if(G[u][v]&&!vis[u])
{
vis[u]
=1;
reach[u]
=1;
dfs(u);
}
}
int main()
{
int i,j,k,u,v,num,front,rear,flag;
while(1)
{
scanf(
"%d",&n);
if(n==-1)
break;
memset(G,
0,sizeof(G));
for(u=1;u<=n;u++)
{
scanf(
"%d",&w[u]);
scanf(
"%d",&num);
for(i=0;i<num;i++)
{
scanf(
"%d",&v);
G[u][v]
=1;
}
}
memset(vis,
0,sizeof(vis));
memset(reach,
0,sizeof(reach));
reach[n]
=1;
dfs(n);
if(!reach[1])
{
printf(
"hopeless\n");
continue;
}
memset(inq,
0,sizeof(inq));
memset(inedq,
0,sizeof(inedq));
memset(d,
0,sizeof(d));
front
=rear=0;
d[
1]=100;
q[rear
++]=1;
inq[
1]=1;
inedq[
1]++;
flag
=0;
while(front!=rear)
{
u
=q[front++];
if(front>n)
front
=0;
inq[u]
=0;
for(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[rear
++]=v;
if(rear>n)
rear
=0;
inq[v]
=1;
if(inedq[v]++>n)
{
flag
=1;
break;
}
}
}
if(d[n]>0||flag)
break;
}
if(d[n]>0||flag)
printf(
"winnable\n");
else
printf(
"hopeless\n");
}
return 0;
}

  

posted on 2011-09-09 20:49  Staginner  阅读(692)  评论(0编辑  收藏  举报