P6970 [NEERC2016] Game on Graph

P6970 [NEERC2016] Game on Graph

[NEERC2016] Game on Graph

题面翻译

Gennady 和 Georgiy 在玩一个有向图上的游戏。这个图有 \(n\) 个点 \(m\) 条边,两人轮流操作,每次可以将棋子沿着其中一条边移动,不能移动者输。

你要对于每个点,分别求出以这个店为起点开始游戏,两人分别作为先手,最终会输,赢,还是平局(游戏无限循环)。

其中,Gennady 因为玩得很开心,所以他更期望将游戏变为平局;Georgiy 还有很多其他事,所以他更期望游戏不要平局。当然,在不平局的基础上,两人都更希望赢。

输入格式

第一行两个数 \(n\)\(m\) 表示有 \(n\) 个点 \(m\) 条边。
接下来 \(m\) 行每行两个数 \(a,b\) 表示一条由 \(a\)\(b\) 的边。

输出格式

两行,第一行表示分别以每一个点为起点 Gennady 先手的胜负情况;第二行表示分别以每一个点为起点 Georgiy 先手的胜负情况。W 表示赢,L 表示输,D 表示平局。

by a___

(1≤n≤100000)
(1≤m≤200000)
Time limit: 2 s, Memory limit: 512 MB.
---------------------------------------------------------------------------------------

将每个点拆成A,B两类;
对于一个点u及其邻居v:

用opt=0代表A类节点,opt=1代表B类节点

对于A类点v.A:
如果它的所有u.A已经被遍历过了,那就搜索v.a这个节点。
(因为A希望平局,所以要先确定他邻居点的状态再确定他)

对于B类点v.B:
如果它没有被访问过,那就访问v.B这个节点
(因为B不希望平局,所以只要能访问就访问)

注意:在主程序中用for遍历启动搜索时,只有那些d==0的节点才能被搜
(即状态已经确定的节点)

然后,我们在第一次搜索完之后统计所有节点的胜负
而对于胜负的判定:(对于第一次搜素)

若对于 vis[0][opt]=1:
说明其被访问过即度数已经为0则A输了,反之,暂定A赢了

若对于 vis[1][opt]=1:
说明其被访问过即度数已经为0则B赢了,反之,暂定B输了

(因为B在第一次dfs中为后手,所以要反过来)

再进行第二次搜索,而在两次搜索中都未被确定的节点就是平局了

然后这题就做完了

Code:

#include<bits/stdc++.h>
const int N=1e5+5;
using namespace std;
vector<int> E[N];
int d[N][2],vis[N][2];
char ans[2][N]; 
int n,m;
void dfs(int u,int opt)
{
	vis[u][opt]=1;
	for(int v : E[u])
	{
		d[v][opt^1]--;
		if(opt==0&&vis[v][1]==0)dfs(v,1);//对于B类点,只要先前没遍历过,就搜一下 
		if(opt==1&&d[v][0]==0)dfs(v,0);//对于A类点,要等到所有邻居被访问过之后才能搜 
	}
} 
void work()
{
	cin>>n>>m;
	for(int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		E[y].push_back(x);//建反图,由已知确定未知 
		d[x][1]++,d[x][0]++;//两类点的度数 
	}
	for(int i=1;i<=n;i++)
	{
		if(d[i][0]==0&&vis[i][0]==0)
		{
			dfs(i,0);
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(vis[i][0])
		{
			ans[0][i]='L';
		}
		else 
		{
			ans[0][i]='W';
		}
	 	if(vis[i][1]) 
		{
			ans[1][i]='W'; 
		}
		else
		{
			ans[1][i]='L'; 
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(!d[i][1]&&!vis[i][1])dfs(i,1);
	} 
	for(int i=1;i<=n;i++)
	{
		if(!vis[i][1])ans[1][i]='D';
		if(!vis[i][0])ans[0][i]='D';
	}
	for(int opt=0;opt<2;opt++)
	{
		for(int i=1;i<=n;i++)
		{
			putchar(ans[opt][i]);
		}
		cout<<"\n";
	}
}
int main()
{
	//freopen("P6970.in","r",stdin);//freopen("P6970.out","w",stdout);
	work();
}
posted @ 2024-12-06 11:45  liuboom  阅读(33)  评论(0)    收藏  举报