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;
}

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