题意:有N个房间,刚开始你位于1号房间,有100的能量值,你要到达N号房间,每两个房间之间有单向门相连接,你到达某个房间可以加上该房间的能量值,如果你在未到达N号房间之前能量值耗尽,则死亡,否则胜利。
spfa思路:通过不断地进行松弛操作,使得存在回路的点对应的能量值不断变大变大,或者是能量不断变大的次数超过一个给定的值(这个值要很大很大,我设置的是10000),到达终点能量依然大于0为止。到不了终点或者到终点能量值耗尽,则死亡,否则胜利。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3;
#define inf 0x3f3f3f3f
int n,m;
int d[maxn],vis[maxn],cnt[maxn];
vector<pair<int,int> >E[maxn];
void init()
{
for(int i = 0; i < maxn; i++) vis[i] = 0, cnt[i] = 0;
for(int i = 0; i < maxn; i++) d[i] = 0;
for(int i = 0; i < maxn; i++) E[i].clear();
}
void spfa()
{
d[1] = 100; vis[1] = 1;
queue <int> Q;
Q.push(1);
while(!Q.empty())
{
int now = Q.front();
Q.pop(); vis[now] = 0;
for(int j = 0; j < E[now].size(); j++)
{
int v = E[now][j].first;
if(d[v] < d[now] + E[now][j].second && cnt[v] < 10000)
{
cnt[v]++;
d[v] = d[now] + E[now][j].second;
if(vis[v]) continue;
vis[v] = 1;
Q.push(v);
}
}
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n == -1) break;
init();
int a,b,x;
for(int i = 1; i <= n; i++)
{
scanf("%d%d",&x,&m);
for(int j = 1; j <= m; j++)
{
scanf("%d",&b);
E[i].push_back(make_pair(b,x));
}
}
spfa();
if(d[n] > 0) puts("winnable");
else puts("hopeless");
}
return 0;
}
dfs思路:当发现有个和为正值的环存在时,直接求看该点能否直接到达终点。如果可以,直接返回true,即胜利。否则,继续搜索,当发现所有路径都不能到达终点时,返回false。虽然能ac但不正确。
判断正环的地方 d[u]+e[v]>d[v]
只是点u存在到点v的边,从点u到点v会使点v的值增大,但是点v不一定存在路径能回到点u,这个不一定是一个环。
一组很简单的数据
7
0 2 2 4
-10 1 3
-10 1 6
-10 1 5
30 1 3
-200 1 7
0 0
应该输出失败但是输出了成功
就是在点5到点3过程中,可以使点3的值增大,就判定点5和点3之间有正环,然后从点3找到了到终点7的通路,就判为成功,其实点5和点3之间没有正环,整个图都没有环。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3;
#define inf 0x3f3f3f3f
int n,m;
int d[maxn],vis[maxn], energy[maxn];
vector<int >E[maxn];
void init()
{
for(int i = 0; i < maxn; i++) d[i] = 0, energy[i] = 0;
for(int i = 0; i < maxn; i++) E[i].clear();
}
int dfs(int u)
{
if(u == n) return 1;
vis[u] = 1;
for(int i = 0; i < E[u].size(); i++)
{
int v = E[u][i];
if(!vis[v])
{
if(dfs(v))
return 1;
}
}
return 0;
}
int DFS(int u, int e)
{
if(u == n) return 1;
d[u] = energy[u] + e;
for(int i = 0; i < E[u].size(); i++)
{
int v = E[u][i];
if(d[u] + energy[v] > 0)
{
if(!d[v])
{
if(DFS(v, d[u]))
return 1;
}
else if(d[v] < d[u] + energy[v])
{
memset(vis,0,sizeof(vis));
if(dfs(v))
return 1;
}
}
}
return 0;
}
int main()
{
int m,k;
while(~scanf("%d",&n) && n != -1)
{
init();
for(int i = 1; i <= n; i++)
{
scanf("%d%d",&energy[i],&m);
for(int j = 1; j <= m; j++)
{
scanf("%d",&k);
E[i].push_back(k);
}
}
if(DFS(1,100)) puts("winnable");
else puts("hopeless");
}
return 0;
}