HDU - 1317 XYZZY(分清概念,找准知识点---判断正环)

题目链接:https://cn.vjudge.net/contest/315275#problem/F
Sample Input

5
0 1 2
-60 1 3
-60 1 4
20 1 5
0 0
5
0 1 2
20 1 3
-60 1 4
-60 1 5
0 0
5
0 1 2
21 1 3
-60 1 4
-60 1 5
0 0
5
0 1 2
20 2 1 3
-60 1 4
-60 1 5
0 0
-1

Sample Output

hopeless
hopeless
winnable
winnable

翻译:
初始有100能量,每个房间都有一个能量值,走到这个房间可以获得(能量值可以有负)。判断从1能否走到n,每走一步都必须保证能量大于0,小于等于0就不能走。
输入一个n,表示有n个房间,每行第一个数表示房间i的能量值。第二个数表示与房间i相连的房间
分析:每走一步都必须保证能量大于0,最短路肯定不行。第一思路直接改模板变成最长路。要明白你求得的各个顶点的最长路与题目中的描述完全是两个不同的概念。题目要求从1到n走到各个顶点都必须保证自身的能量大于0。可以想到是借助判断是否有正权回路的思想来写(实则从1到n没有成回路,还少一条边)。
1.借助Floyd判断各点的连同情况。
2.SPFA判断各点入队列的次数来判断回路。入队列必须保证:这两点是连同的,走到这一点的获得的能量加上原来的能量必须大于0和原来的能量。(保证每走一步获得的能量都是大于0的,正权回路不能有负数,不然与正权回路相矛盾)。

代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
int e[102][102],a[102][102],pow1[102];
int dis[102],time[102],book[102];
int n;
void Floyd() { /*判断与n相连的点*/
	for(int k=1; k<=n; k++)
		for(int i=1; i<=n; i++)
			for(int j=1; j<=n; j++)
				if(a[i][k]&&a[k][j])
					a[i][j]=1;
}
int SPFA() {
	memset(dis,0,sizeof(dis));
	memset(time,0,sizeof(time));
	memset(book,0,sizeof(book));
	dis[1]=100;
	queue<int>q;
	q.push(1);
	book[1]=1;
	while(!q.empty()) {
		int u=q.front();
		time[u]++;
		q.pop();
		if(time[u]>=n)/*判断成一个正环*/
			return a[u][n];
		for(int i=1; i<=n; i++) {
			if(e[u][i]&&dis[i]<dis[u]+pow1[i]&&dis[u]+pow1[i]>0) { /*两点必须连通,走到下一个房间pow大于0,*/
				dis[i]=dis[u]+pow1[i];
				q.push(i);
			}
		}
	}
	if(dis[n]>0)
		return 1;
	else
		return 0;
}
int main() {
	while(~scanf("%d",&n)) {
		if(n==-1)break;
		memset(e,0,sizeof(e));
		memset(a,0,sizeof(a));
		for(int i=1; i<=n; i++) { /*n个房间*/
			int m;
			scanf("%d%d",&pow1[i],&m);/*第i个房间拥有的能量值*/
			while(m--) {
				int a1;/*与i相连的房间有a1个*/
				scanf("%d",&a1);
				e[i][a1]=1;
				a[i][a1]=1;
			}
		}
		Floyd();
		if(!a[1][n])
			printf("hopeless\n");
		else {
			if(SPFA())
				printf("winnable\n");
			else
				printf("hopeless\n");
		}
	}

	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zaiyang遇见

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值