此题打过游戏的人理解起来不难,就是初始有个血量,然后每到一个房间或者加血或者减血,
给出一个初始能量100的人,能否从1走到n,在这个过程中,血量都必须是大于0的。
这题目算法首先要判断能不能从1到达n,用floyd传递闭包
然后计算一个最长路,保证每个点血量大于0,否则不能到达,还要求松弛的点能够到达n。。。具体见代码
此题用了两种方法,可以修改if(bellMan())或者if(spfa())来实现两种算法,时间差不多。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxN 110//最大定点个数
#define inf -100000000
int mat[maxN][maxN],dis[maxN], flag[maxN][maxN],weight[maxN];
/*
mat[maxN][maxN],标示定点间边
dis[maxN], 标示距离
flag[maxN][maxN],标示可达性
weight[maxN]标示定点能量
*/
int n;
bool bellMan()//bellman算法
{
bool f;
int tot = 0;
for (int i = 1; i <= n; ++ i)
{
dis[i] = inf;
flag[i][i] = 1;
}
dis[1] = 100;
int k;
for (k = 1; k <= n; ++ k)
{
f = false;
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= n; ++ j)
{
if (mat[i][j] && dis[j] < dis[i] + weight[i] && flag[1][j] && flag[j][n] && dis[i] > 0)
{
dis[j] = dis[i] + weight[i];
f = true;
}
}
}
if (!f)
{
break;
}
}
if (k > n || dis[n] > 0)
{
return true;
}
else
return false;
}
bool spfa()
{
int queue[100 * maxN];
bool vis[maxN];
int inTimes[maxN];
for (int i = 1; i <= n; ++ i)
{
dis[i] = inf;
flag[i][i] = 1;
}
memset(vis, false, sizeof(vis));
memset(inTimes, 0, sizeof(inTimes));
int head = 0, tail = 1;
queue[0] = 1;
dis[1] = 100;
while (head < tail)
{
int u = queue[head];
vis[u] = true;
inTimes[u] ++;
if (inTimes[u] > n)
{
break;
}
for (int i = 1; i <= n; ++ i)
{
if (mat[u][i] && dis[i] < dis[u] + weight[i] && dis[u] > 0 && flag[1][i] && flag[i][n])
{
dis[i] = dis[u] + weight[i];
if (!vis[i])
{
vis[i] = true;
//inTimes[i] ++;
queue[tail] = i;
tail ++;
}
}
}
head ++;
vis[u] = false;
}
for (int i = 1; i <= n; ++ i)
{
if (inTimes[i] >= n)
{
return true;
}
}
if (dis[n] >= 0)
{
return true;
}
return false;
}
int main()
{
while (scanf("%d", &n) && n != -1)
{
int w,vNum,v;
memset(mat, 0, sizeof(mat));
memset(flag, 0, sizeof(flag));
for (int i = 1; i <= n; ++ i)
{
scanf("%d%d", &w, &vNum);
for (int j = 0; j < vNum; ++ j)
{
scanf("%d", &v);
mat[i][v] = 1;
flag[i][v] = 1;
weight[i] = w;
}
}
for (int k = 1; k <= n; ++ k)
{
for (int i = 1; i <= n; ++ i)
{
for (int j = 1; j <= n; ++ j)
{
if (flag[i][k] && flag[k][j])
{
flag[i][j] = 1;
}
}
}
}
if (!flag[1][n])
{
printf("hopeless\n");
continue;
}
if (spfa()/*bellMan()*/)
{
printf("winnable\n");
}
else
printf("hopeless\n");
}
return 0;
}