1、这题真心把我坑死了,昨天下午两点开始做的,次日凌晨五点才AC(当然中途有休息),uva数据就是BT。。。
2、刚开始反复RE,终于明白RE不止是数组越界还可能有栈溢出的原因。据说用STL的队列就显示TLE,如果用普通数组模拟就是RE。长知识了。
3、后来反复WA,非常邪门,把bfs改成dfs,再把dfs改成bfs,还是不行,最后只能上网搜解题报告了。
4、递归的部分和解题报告已经是一样的了,居然还是WA,到底是怎么回事?最后想啊想啊终于想到了,原来是“判断是否能到达终点”的时候,应该从“当前结点”开始搜索,而不是从“结点1”开始搜索,因为这是有,向,图!!!我本来以为从“当前结点”肯定能回到“结点1”,太天真了!!!
5、每次都犯这种非常低级的错误= =。。。
6、简单说下思路吧,就是判断是否存在一条从起点到终点的通路,使得边权相加为正,且中途不能有边权和为非正(负数或0)的时候,但由于图可能含有环(正环或负环),所以要加特判。怎么判断有正环呢?只要看再次访问结点的时候,当前权值之和是否大于历史权值之和,如果是,则说明是正环,要判断从“当前结点”是否能到终点(我就是栽在这里)。
7、还有一个要注意的就是每次访问一个新的结点的时候,必须要先判断权值和是否为负,因为如果权值和已经为负,这条路肯定不通了(题目要求,因为血掉光了嘛),所以负环根本不用担心,只要加了这一条if语句,就可以避免死循环了。(我开始就是因为没加这个,从bfs改成dfs再改成bfs,怎么都是死循环,这也是个教训了。)
8、用邻接表保存结点比较方便。
9、还有注意一些计数的变量如i,j不要用全局变量,函数一多很容易搞混。
10、有大神说用SPFA可以做。。。但我不会(囧),感觉自己真是弱爆了。。。
#include<cstdio>
#include<cstring>
int n,t;
int a[110][110],val[110],c[110],e[110],q[110];
bool judge,flag;
void init(void)
{
int i,j;
for(i=1;i<=n;i++)
{
scanf("%d%d",&val[i],&a[i][0]);
for(j=1;j<=a[i][0];j++)
{
scanf("%d",&a[i][j]);
}
}
return;
}
bool have_exit(int num)
{
int v,i,front=0,rear=0;
c[num]=1;q[rear++]=num;
while(front<rear)
{
v=q[front++];
for(i=1;i<=a[v][0];i++)
{
if(!c[a[v][i]])
{
if(a[v][i]==n)return true;
q[rear++]=a[v][i];
c[q[rear-1]]=1;
}
}
}
return false;
}
bool dfs(int num,int energy)
{
int u,i;
if(num==n&&energy>0) return true;
for(i=1;i<=a[num][0];i++)
{
u=a[num][i];
if(energy+val[u]>0)
{
if(!e[u])
{
e[u]=energy+val[u];
if(dfs(u,e[u])) return true;
}
else if(e[u]<energy+val[u]&&have_exit(u))
{
return true;
}
}
}
return false;
}
void print(void)
{
if(dfs(1,100))
printf("winnable\n");
else
printf("hopeless\n");
}
int main(void)
{
//freopen("a.txt","r",stdin);
while(scanf("%d",&n)==1)
{
if(n==-1)break;
memset(a,0,sizeof(a));
memset(val,0,sizeof(val));
memset(c,0,sizeof(c));
memset(e,0,sizeof(e));
memset(q,0,sizeof(q));
init();
e[1]=100;
print();
}
}