#博弈论,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;
}

浙公网安备 33010602011771号