P6970 [NEERC2016] Game on Graph

liuboom發表於2024-12-06

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();
}

相關文章