计蒜客闯关游戏

问题描述
蒜头君在玩一个很好玩的游戏,这个游戏一共有至多 100 个地图,其中地图 1 是起点,房间 n 是终点。有的地图是补给站,可以加 ki点体力,而有的地图里存在怪物,需要消耗 ki 点体力,地图与地图之间存在一些单向通道链接。 
蒜头君从 1 号地图出发,有 100 点初始体力。每进入一个地图的时候,需要扣除或者增加相应的体力值。这个过程持续到走到终点,或者体力值归零就会 Game Over。不过,他可以经过同个地图任意次,且每次都需要接受该地图的体力值。 
输入格式 
第 1 行一个整数 n (n≤100)。 
第 2 ~ n+1 行,每行第一个整数表示该地图体力值变化。接下来是从该房间能到达的房间名单,第一个整数表示房间数,后面是能到达的房间编号。 
输出格式 
若玩家能到达终点,输出Yes,否则输出No。 
样例输入 

0 1 2 
-60 1 3 
-60 1 4 
20 1 5 
0 0 
样例输出 

No

思路:

参考spfa算法,将节点增加或减少的值作为路径长度,我们要做的是找到每个点到起点的最大路径。在更新的过程中,若更新的某个点的最大路径为负数,说明不能到达此房间,不要入队。若最后不能到达目标点或者目标点的最大路径为负,则判断为No

注意:

若有正环,说明可在此无限增加体力,可直接判断为Yes。

代码:

#include
using namespace std;
const int N=110; const int MIN=-0x7ffffff;
struct Way{
	int to,next;
} way[N*N];
int n,m,k,cnt,cur,val[N],dis[N],head[N],num[N];
void add(int u,int v){
	way[++cnt].next=head[u];
	way[cnt].to=v;
	head[u]=cnt;
}
queueq;
void spfa(int st){
	for(int i=1;i<=n;i++) dis[i]=MIN;
	q.push(st); dis[st]=100;
	while(!q.empty()){
		cur=q.front(); q.pop(); num[cur]++;
		if(num[cur]>=n){
			printf("Yes"); return;
		}
		for(int i=head[cur];i;i=way[i].next)
			if(dis[way[i].to]0){
				dis[way[i].to]=dis[cur]+val[way[i].to];
				q.push(way[i].to);
			}
	}
	if(dis[n]>0) printf("Yes");
	else printf("No");
}
int main(){
	freopen("data.in","r",stdin); 
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d %d",&val[i],&m);
		for(int j=1;j<=m;j++){
			scanf("%d",&k); add(i,k);
		}
	}
	spfa(1);
	return 0;
}

你可能感兴趣的:(题解)