The game is played on a chessboard with R rows and C columns, for a total of RC squares. Some of these squares are considered unlucky,so the chessman can't be moved to there.
The rule of this game is simple,diffrent from traditional chess,there is only a King on the chessboard beacuse daizhenyang thinks various chessmans leads to complex rule which makes poor daizhenyang hard to understand.
Also daizhenyang want's make the only chessman more powerful in order to become more unbeatable,The King is no longer the traditional weak king,it integrates the power of Guard,bishop,pawn,as well as knight.And the move range is not confined.It can move to anywhere which is considered lucky. So, according to the graph, the red king can move to 20 adjacent places.
And the aim of this game is simple too,The so-called King is placed in a random square of the chessboard which is considered lucky.Two players move the King alternately,in any move,the destination square must not be unlucky,and the king must never have been in the destination square before,which will causes dead loops.The first people who can't do a valid move lose.
daizhenyang is playing chess with another people,who is too shy to told his name.And daizhenyang moves first,he asks you--the genius programmer,for help.
please write a program to judge whether daizhenyang will win.Assume both player will play optimally.
The first line of input gives the number of cases, N.
'#' means the square is considered unlucky;
'.' means the square is considered lucky, and unoccupied; and
'K' means the king is in that square at the beginning of the game.
There will be only one 'K' character in each test case.
//
判断一个点是否可以成为一般图最大匹配中的点:算一下去除这个点和不去除这个点的最大匹配即可,若两次不一样,则这个点可以是最大匹配中的一个点,即至少明存在一条增广路,且增广路的起点为king所在的点,那么,我们沿着这条路走下去,最后后手必然无路可走。
若K可以是最大匹配中的一个点,则先手走K匹配的点,然后无论后手怎么走,先手只选其匹配的点,先手胜。
若K可以不是最大匹配中的一个点,则先手第一次只能走最大匹配中的一个点或无路可走,后手只要选起匹配的点即可,后手胜。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=250;
int n;//点数(1->n)
int head;
int tail;
int Start;
int Finish;
int link[N]; //表示哪个点匹配了哪个点
int Father[N]; //这个就是增广路的Father……但是用起来太精髓了
int Base[N]; //该点属于哪朵花
int Q[N];
bool mark[N];
bool mat[N][N];//邻接矩阵
bool InBlossom[N];
bool in_Queue[N];
void BlossomContract(int x,int y){
memset(mark,0,sizeof(mark));
memset(InBlossom,0,sizeof(InBlossom));
#define pre Father[link[i]]
int lca,i;
for (i=x;i;i=pre) {i=Base[i]; mark[i]=true; }
for (i=y;i;i=pre) {i=Base[i]; if (mark[i]) {lca=i; break;} } //寻找lca之旅……一定要注意i=Base[i]
for (i=x;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //对于BFS树中的父边是匹配边的点,Father向后跳
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
for (i=y;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //同理
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
#undef pre
if (Base[x]!=lca) Father[x]=y; //注意不能从lca这个奇环的关键点跳回来
if (Base[y]!=lca) Father[y]=x;
for (i=1;i<=n;i++)
if (InBlossom[Base[i]]){
Base[i]=lca;
if (!in_Queue[i]){
Q[++tail]=i;
in_Queue[i]=true; //要注意如果本来连向BFS树中父结点的边是非匹配边的点,可能是没有入队的
}
}
}
void Change(){
int x,y,z;
z=Finish;
while (z){
y=Father[z];
x=link[y];
link[y]=z;
link[z]=y;
z=x;
}
}
void FindAugmentPath(){
memset(Father,0,sizeof(Father));
memset(in_Queue,0,sizeof(in_Queue));
for (int i=1;i<=n;i++) Base[i]=i;
head=0; tail=1;
Q[1]=Start;
in_Queue[Start]=1;
while (head!=tail){
int x=Q[++head];
for (int y=1;y<=n;y++)
if (mat[x][y] && Base[x]!=Base[y] && link[x]!=y) //无意义的边
if ( Start==y || link[y] && Father[link[y]] ) //精髓地用Father表示该点是否
BlossomContract(x,y);
else if (!Father[y]){
Father[y]=x;
if (link[y]){
Q[++tail]=link[y];
in_Queue[link[y]]=true;
}
else{
Finish=y;
Change();
return;
}
}
}
}
void Edmonds(){
memset(link,0,sizeof(link));
for (Start=1;Start<=n;Start++)
if (link[Start]==0)
FindAugmentPath();
}
int MaxMatch()
{
Edmonds();
int cnt=0;//一般图最大匹配 最大点数
for (int i=1;i<=n;i++)
if (link[i]) cnt++;
return cnt;
}
void output(){
memset(mark,0,sizeof(mark));
int cnt=0;//一般图最大匹配 最大点数
for (int i=1;i<=n;i++)
if (link[i]) cnt++;
printf("%d\n",cnt);
for (int i=1;i<=n;i++)
if (!mark[i] && link[i]){
mark[i]=true;//i和link[i]匹配
mark[link[i]]=true;
printf("%d %d\n",i,link[i]);
}
}
char str[50][50];
const int dx[]={-1,-1,-1,1,1,1,0,0,2,-2,2,-2,2,-2,2,-2,1,-1,-1,1};
const int dy[]={-1,1,0,0,1,-1,-1,1,2,2,-2,-2,1,-1,-1,1,2,-2,2,-2};
int main()
{
int ci,pl=1;scanf("%d",&ci);
while(ci--)
{
int r,c;scanf("%d%d",&r,&c);
n=r*c;//
for(int i=0;i<r;i++) scanf("%s",str[i]);
int maxMatch,maxMatchK;
//不算K
memset(mat,0,sizeof(mat));
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
{
int p1=i*c+j+1;
if(str[i][j]=='#'||str[i][j]=='K') continue;
for(int k=0;k<20;k++)
{
int x=i+dx[k],y=j+dy[k];
if(x>=0&&x<r&&y>=0&&y<c){
if(str[x][y]=='#'||str[x][y]=='K') continue;
int p2=x*c+y+1;
mat[p1][p2]=1;
}
}
}
}
maxMatch=MaxMatch();
//算上K
memset(mat,0,sizeof(mat));
for(int i=0;i<r;i++)
{
for(int j=0;j<c;j++)
{
int p1=i*c+j+1;
if(str[i][j]=='#') continue;
for(int k=0;k<24;k++)
{
int x=i+dx[k],y=j+dy[k];
if(x>=0&&x<r&&y>=0&&y<c){
if(str[x][y]=='#') continue;
int p2=x*c+y+1;
mat[p1][p2]=1;
}
}
}
}
maxMatchK=MaxMatch();
if(maxMatch==maxMatchK)
printf("Case #%d: daizhenyang lose\n",pl++);
else printf("Case #%d: daizhenyang win\n",pl++);
}
return 0;
}