hdu 3446 daizhenyang's chess 一般图最大匹配+博弈 在一个棋盘上,两个人轮流走,每个人可以移动king走到没被走过的幸运的格子上。问,先手是否能赢。

Problem Description
As we know,daizhenyang likes playing chess,but he always lose,so one day,he invented a brand new chess game with the new rule.

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.
 


 

Input
N test cases follow. The first line of each case will contain two integers, R and C. The next R lines will contain strings of length C, representing the C squares of each row.(1<=R,C<=15) Each string will contain only the characters '.', '#' and 'K':
'#' 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.
 


 

Output
For each test case, output one line containing "Case #X: " (where X is the case number, starting from 1) followed by "daizhenyang win" if daizhenyang wins, or "daizhenyang lose" if daizhenyang lose.
 


 

Sample Input
2 2 2 K. .# 4 2 K# .# .# .#
 


 

Sample Output
Case #1: daizhenyang lose Case #2: daizhenyang win
Hint
In case 1,daizhenyang can do 2 choices,but no matter what he choose,the opponent will move to another,which makes daizhenyang unable to move. In case 2,daizhenyang moves down,opponent moves down,daizhenyang moves down,he win!

 

 //

判断一个点是否可以成为一般图最大匹配中的点:算一下去除这个点和不去除这个点的最大匹配即可,若两次不一样,则这个点可以是最大匹配中的一个点,即至少明存在一条增广路,且增广路的起点为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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章