power oj 2826: 有趣的游戏 spfa+暴力判环(或tarjan缩点)

2826: 有趣的游戏

Time Limit: 2000 MS Memory Limit: 9000 KB
Total Submit: 72 Accepted: 1 Page View: 181
Submit Status Discuss

Description

    一天wangshu迷上了一个十分有趣的游戏,名为sdfsfgdsfsdfsdfse,在在游戏里你需要从一个起始补给点开始去寻找装备,每一个补给点都有一定价值的装备,最后从出口补给点出去,这个游戏十分有趣,所以当你离开一个补给点后这个补给点会重生和原来一样价值的装备,当你达到一个补给点后就会立即得到当前补给点价值的奖励,然后去下一个补给点,当然从一个补给点到下一个补给点的路径是单向的,你只能沿着这条路过去不能沿着这条路回来,当然你可能会得到无限多的奖励,到了出口也可以先不出去,继续去下一个补给点,同样也可能无法到达出口补给点,无法到达出口点当然是毫无意义的。

Input

第一行两个数n,m,分别表示有n个补给点,m条路,其中编号为1的补给点为起点,编号为n的补给点为出口点。 第二行包括n个数依次表示1到n号补给点的可得的奖励值ai, 接下来mm行每行两个数,st,en表示可以从补给点st到补给点en。 保证不会出现重边和自环。

Output

如果可以得到无穷大的奖励并能出去输出"Infinitely",如果不能到达出口则输出"Unreachable",否则输出能得到的最大奖励。

3 2

1 2 3

1 2

2 3

3 3

1 2 3

1 2

2 3

3 2

6

Infinitely

Hint

0<n≤5×1e3,0≤m≤1e4 0<ai≤1e7+5,1≤st,en≤n.均为整数

题意:就是求有向图点有权边无权的最长路。

思路:有两种情况,第一种是可能到不了终点的有可能在路径上有环,所以不能让他遇到环就输出无法到达,一种是可以到达终点但是可能在任意可到达终点上的路径存在一个环,答案就是无穷大,只要在可以所有能到达终点的路径上没有的环才是可能有最大值,其他不能到达终点的无所谓,注意就算到了终点也是可以继续走的,如果环里终点的话也是无穷大,题面说的十分清楚。

题解:这道题最重要的是正确的判环,怎么处理环,qwy写了一个暴力的dfs先判断哪些点可以到终点,不能到终点的标记,第二次dfs只走哪些可以到终点的点,如果遇到环了就还回无穷大,因为走的点都是可以到终点的,然后过了跑了1500ms,lx也是写的差不多的dfs好像比不过优化了很多,只有差不多几百ms,我的标程是暴力spfa更新n次为环,或者tarjan缩点+spfa,spfa大家都懂吧把大于改成小于就好了,只是这个判环,假如我们这个有向图没有环的话,求最大值,一个点的dis更新一定不会超过n次(仔细想一下,的确是这样),如果有环的这个点一定会更新无穷多次,那么记录一个点更新的次数,一旦更新了n次就标记为环,dis更新为无穷大,然后无穷大的点的能到的点也一定是可以更新到无穷大的一直更新下去直到队列为空。最后查看dis[n],最坏的情况就是每个点更新n次,只有5000个点1w条边,2000ms,O(n*n)的复杂度完全可以过,标程跑了差不多500ms。然后tarjan缩点+spfa,(还不会tarjan的先去学习下,这也是一个比较重要的算法),先跑一变tarjan吧所有构成环的点缩成一个点,然后跑spfa,只要是环的就直接更新为无穷大然后,直到循环结束,复杂度为O(n),我的标程差不多跑了100ms。jxj写了个tarjan+spfa代码+其他的长度2800+B的也过了只跑了20ms。

一共39组数据,第一组数据就是5000个点和4999条边连成了一条线,还有一组是起点连了1500个小环和终点,第21组是140个点9730条边的超级稠的图,还有很多错综复杂的图,不过我没有那么伤心病狂出网格图卡spfa。还有一点比赛的时候内存给的是两个G其实最开始我只打算给9000kb的,然后应洋哥要求改的,现在改回9000kb了,其实作用不大,只能卡你暴力spfa的时候你没标记在队,如果你有其他写法完全卡不了你,如果你暴力spfa没标记在队的话跑出来内存为9700kb,学长用的其他各种方法都在5000kb以下,也不是专门为了卡你,不过其他比赛的时候出题人一定会造更大更严谨的数据卡你,以及给你更严格的时间空间限制,主要是想提醒大家以下。

代码:

暴力spfa更新n次判环:

#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const ll linf=8e18+9e17;
const ll mod=1e9+7;
const double e=exp(1.0);
const double pi=acos(-1);
vector<int>v[5005];
int n,a[5005],num[5005]={0};
ll dis[5005]={0};
bool use[5005];
void spfa()
{
	queue<int>q;
	q.push(1);
	use[1]=1;
	while(!q.empty())
	{
		int now,next;
		now=q.front();
		q.pop();
		use[now]=0;
		for(int i=0;i<v[now].size();i++)
		{
			next=v[now][i];
			if(dis[next]!=linf&&dis[now]+a[next]>dis[next]){
				
				if(dis[now]==linf)dis[next]=linf;
				else dis[next]=dis[now]+a[next];
				
				num[next]++;
				if(num[next]>n)dis[next]=linf;
				
				if(!use[next]){
					q.push(next);
					use[next]=1;					
				}
			}
		}
	}
}
int main()
{
	//freopen("39.out.txt","w",stdout);
	//freopen("39.in.txt","r",stdin);
	int m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)
	{
		int st,en;
		scanf("%d%d",&st,&en);
		v[st].push_back(en);
	}
	memset(dis,-1,sizeof dis);
	dis[1]=a[1];
	spfa();
	if(dis[n]==linf)printf("Infinitely\n");
	else if(dis[n]==-1)printf("Unreachable\n");
	else printf("%d\n",dis[n]);
	return 0;
}

tarjan缩点+spfa:

#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const ll linf=8e18+9e17;
const int mod=1e9+7;
const double e=exp(1.0);
const double pi=acos(-1);
ll dis[5005];
int a[5005],low[5005],dfn[5005],tim,cnt/*,belong[5005]*/;
bool instack[5005],use[5005];
stack<int>s;
vector<int>v[5005];
//vector<int>v1[maxn];
void tarjan(int st)
{
	low[st]=dfn[st]=++tim;
	instack[st]=1;
	s.push(st);
	for(int i=0;i<v[st].size();i++)
	{
		int next=v[st][i];
		if(!dfn[next]){
			tarjan(next);
			if(low[next]<low[st])low[st]=low[next];
		}
		else if(instack[next]&&dfn[next]<low[st])low[st]=dfn[next];
	}
		if(low[st]==dfn[st])
		{
			cnt++;
			int now=inf;
			while(now!=st)
			{
			now=s.top();
			s.pop();
			instack[now]=0;
			//belong[now]=cnt;
			//v1[cnt].push_back(now);
			}
		}
}
void spfa()
{
	queue<int>q;
	q.push(1);
	use[1]=1;
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		use[now]=0;
		for(int i=0;i<v[now].size();i++)
		{
			int next=v[now][i];
			if(dis[next]!=linf&&dis[now]+a[next]>dis[next]){
				
				if(dis[now]==linf||low[now]==low[next])dis[next]=linf;
				else dis[next]=dis[now]+a[next];
				
				if(!use[next]){
					q.push(next);
					use[next]=1;
				}
			}
		}
	}
}
int main()
{
	//freopen("39.in.txt","r",stdin);
	int n,m,st,en;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&st,&en);
		v[st].push_back(en);
	}
	tarjan(1);
	memset(dis,-1,sizeof dis);
	dis[1]=a[1];
	spfa();
	if(dis[n]==linf)printf("Infinitely\n");
	else if(dis[n]==-1)printf("Unreachable\n");
	else printf("%lld\n",dis[n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/swust5120166213/article/details/81697661