Gennady and Georgiy are playing interesting game on a directed graph. The graph has n vertices and m arcs, loops are allowed. Gennady and Georgiy have a token placed in one of the graph vertices. Players take turns moving the token along one of the arcs that starts in the vertex the token is currently in. When there is no such arc, then this player loses the game. For each initial position of the token and the player who is moving first, your task is to determine what kind of result the game is going to have. Does it seem to be easy? Not so much. On one side, Gennady is having a lot of fun playing this game, so he wants to play as long as possible. He even prefers a strategy that leads to infinite game to a strategy that makes him a winner. But if he cannot make the game infinite, then he obviously prefers winning to losing. On the other side, Georgiy has a lot of other work, so he does not want to play the game infinitely. Georgiy wants to win the game, but if he cannot win, then he prefers losing game to making it infinite. Both players are playing optimally. Both players know preferences of the other player.
Input
In the first line there are two integers — the number of vertices n (1 ≤ n ≤ 100000) and the number of arcs m (1 ≤ m ≤ 200000). In the next m lines there are two integers a and b on each line, denoting an arc from vertex a to vertex b. Vertices are numbered from 1 to n. Each (a,b) tuple appears at most once.
Output
In the first line print n characters — i-th character should denote the result of the game if Gennady starts in vertex i. In the second line print n characters — i-th character should denote the result of the game if Georgiy starts in vertex i. The result of the game is denoted by “W” if the starting player wins the game, “L” if the starting player loses the game, and “D” (draw) if the game runs infinitely.
题意: 给定有向图,选定起点,每次可以沿着有向图走到下一个点,没有点走的人输。这样很常规的SG图就可以搞定,但是现在加入新规定,A选手如果可以走无限步也算赢。而B选手宁愿输也不愿意走无限步。 现在对于每个点作为起点,输出A做为先手的结果,以及B选手作为先手的结果。
思路: 有向图,而且有环,不能简单的拓扑 :首先我们想一下SG图的概念,如果后续节点有一个为输,那么当前结点就为赢;如果后续节点都为赢,那么当前节点就为输。
对于平局的情况,我们去找A可以平的点,以及B必平的点:
默认每个点都会平,把入度为0的点加入队列,状态为不平,然后从跑队列。对于当前节点,如果是A,当后缀节点有一个的平是,则其是平;如果是B,后缀节点都跑完了,而且都是平,则其是平。其他的都是不平。
对于输赢的情况,我们去找A必输和B可以输的点:
默认每个点都不知道,把入度为0的点加入队列,状态为输,然后跑队列。对于A,如果上面得出它可以平,则平。否则,如果后缀节点有输,则赢。否则输; 对于B,如果上面得出它必须平,则平。否则后缀节点有输,则赢。否则,输。
(666
#include<bits/stdc++.h> #define pii pair<int,int> #define mp make_pair #define A 0 #define B 1 #define fi first #define se second #define Lose 0 #define Win 1 using namespace std; const int maxn=1000010; int draw[maxn][2],vict[maxn][2],c[maxn][2]; int outd[maxn],tag[maxn],head,tail; pii q[maxn]; vector<int>G[maxn]; int main() { int N,M,u,v,i,j; scanf("%d%d",&N,&M); for(i=1;i<=M;i++){ scanf("%d%d",&u,&v); G[v].push_back(u); outd[u]++; } for(i=1;i<=N;i++){ draw[i][A]=draw[i][B]=1;//默认会平 tag[i]=outd[i]; if(!outd[i]){ q[++head]=mp(i,A); q[++head]=mp(i,B); draw[i][A]=0; draw[i][B]=0;//平不了。 } } while(tail<head){ pii now=q[++tail]; for(i=0;i<G[now.fi].size();i++){ if((now.se==A&&draw[G[now.fi][i]][B])||(now.se==B&&!(--outd[G[now.fi][i]]))){ draw[G[now.fi][i]][now.se^1]=0; q[++head]=mp(G[now.fi][i],now.se^1); } } } //平局算完,来算victory。 head=tail=0; for(i=1;i<=N;i++){ outd[i]=tag[i]; vict[i][A]=-1; vict[i][B]=-1; //默认不知道输赢 ,去找必输必赢的点 } for(i=1;i<=N;i++){ for(j=0;j<G[i].size();j++){ if(!draw[i][B]) c[G[i][j]][A]++; if(!draw[i][A]) c[G[i][j]][B]++; //如果非平的点后缀全是赢,则输 } if(!outd[i]){ vict[i][A]=Lose,q[++head]=mp(i,A); vict[i][B]=Lose,q[++head]=mp(i,B); } } while(tail<head){ pii now=q[++tail]; for(i=0;i<G[now.fi].size();i++){ if(draw[G[now.fi][i]][1-now.se]) continue; if(vict[now.fi][now.se]==Win){ if(!(--c[G[now.fi][i]][1-now.se])){ vict[G[now.fi][i]][1-now.se]=0; q[++head]=mp(G[now.fi][i],1-now.se); } } else if(vict[G[now.fi][i]][1-now.se]==-1){ vict[G[now.fi][i]][1-now.se]=1; q[++head]=mp(G[now.fi][i],1-now.se); } } } for(i=1;i<=N;i++) { if(vict[i][A]==-1) vict[i][A]=1; if(vict[i][B]==-1) vict[i][B]=0; } for(j=0;j<2;j++,puts("")) for(i=1;i<=N;i++) { if(draw[i][j]) putchar('D'); else if(vict[i][j]) putchar('W'); else putchar('L'); } return 0; }