#博弈论,DFS#洛谷 6970 [NEERC 2016] Game on Graph

题目传送门


分析

\(win1[0/1][x]\) 表示先手/后手从 \(x\) 这个点开始是否能让后手赢。先手从出点开始的话显然是后手赢,

由于平局的设置,那么只要后手无论如何都能赢先手就是输,否则只要这步先手能输那么上一步后手就必胜。

然后再考虑平局,设 \(draw[0/1][x]\) 表示先手/后手从 \(x\) 这个点开始是否能平局。

后手从出点开始的话显然是先手赢,此时用相同的步骤消除平局即可。

到不了的点都是平局。而到得了的点都会在先手/后手必胜的状态反推得到。


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N=100011;
struct node{int y,next;}e[N<<1];
int n,m,deg[2][N],as[N],win1[2][N],draw[2][N];
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void dfs1(int z,int x){
	win1[z][x]=1;
	if (z){
		for (int i=as[x];i;i=e[i].next)
		    if (--deg[0][e[i].y]==0) dfs1(0,e[i].y);
	}else{
		for (int i=as[x];i;i=e[i].next)
		    if (!win1[1][e[i].y]) dfs1(1,e[i].y);
	}
}
void dfs2(int z,int x){
	draw[z][x]=0;
	if (z){
		for (int i=as[x];i;i=e[i].next)
		    if (--deg[0][e[i].y]==0) dfs2(0,e[i].y);
	}else{
		for (int i=as[x];i;i=e[i].next)
		    if (draw[1][e[i].y]) dfs2(1,e[i].y);
	}
}
int main(){
	n=iut(),m=iut();
	for (int i=1;i<=m;++i){
		int x=iut(),y=iut();
		e[i]=(node){x,as[y]},as[y]=i;
		++deg[0][x],++deg[1][x];
	}
	for (int i=1;i<=n;++i)
	    if (!deg[0][i]&&!win1[0][i]) dfs1(0,i);
	for (int i=1;i<=n;++i) draw[0][i]=win1[0][i]^1,draw[1][i]=win1[1][i]^1;
	for (int i=1;i<=n;++i)
	    if (!deg[1][i]&&draw[1][i]) dfs2(1,i);
	for (int i=1;i<=n;++i)
	if (draw[0][i]) putchar('D');
	    else putchar(win1[0][i]?'L':'W');
	putchar(10);
	for (int i=1;i<=n;++i)
	if (draw[1][i]) putchar('D');
	    else putchar(win1[1][i]?'W':'L');
	putchar(10);
	return 0;
}
posted @ 2025-07-01 03:07  lemondinosaur  阅读(10)  评论(0)    收藏  举报