HDU 3446 daizhenyang's chess(一般图匹配)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3446

题意:有一个R*C的棋盘,棋盘上有一些格子是幸运的格子,棋盘上只有一个棋子king。king有一定的走路规则。两个人轮流走,每个人可以移动king走到没被走过的可达的幸运的格子上。问先手是否能赢?
思路:把所有能连的边先连上,先不算king,求一次匹配。然后再算上king,求一次匹配。如果第二次匹配的结果比第一次大,说至少明存在一条增广路,且增广路的起点为king所在的点,那么,我们沿着这条路走下去,最后后手必然无路可走。
#include <iostream>

#include <cstdio>

#include <queue>

#include <string.h>

#define SET(a,b) memset(a,b,sizeof(a));

using namespace std;



const int MAX=250;

queue<int> Q;

int g[MAX][MAX],inque[MAX],inblossom[MAX];

int match[MAX],pre[MAX],set[MAX];

int n;



int findancestor(int u,int v)

{

    int visit[MAX]={0};

    while(1)

    {

        u=set[u];

        visit[u]=1;

        if(match[u]==-1) break;

        u=pre[match[u]];

    }

    while(1)

    {

        v=set[v];

        if(visit[v]) break;

        v=pre[match[v]];

    }

    return v;

}





void reset(int u,int root)

{

    int v;

    while(u!=root)

    {

        v=match[u];

        inblossom[set[u]]=1;

        inblossom[set[v]]=1;

        v=pre[v];

        if(set[v]!=root) pre[v]=match[u];

        u=v;

    }

}



void contract(int u,int v)

{

    int root=findancestor(u,v);

    int i;

    SET(inblossom,0);

    reset(u,root);

    reset(v,root);

    if(set[u]!=root) pre[u]=v;

    if(set[v]!=root) pre[v]=u;

    for(i=1;i<=n;i++) if(inblossom[set[i]])

    {

        set[i]=root;

        if(!inque[i]) Q.push(i),inque[i]=1;

    }

}



int BFS(int S)

{

    int u,v,i,t;

    for(i=1;i<=n;i++)pre[i]=-1,inque[i]=0,set[i]=i;

    while(!Q.empty()) Q.pop();

    Q.push(S);

    inque[S]=1;

    while(!Q.empty())

    {

        u=Q.front();

        Q.pop();

        for(v=1;v<=n;v++)if(g[u][v]&&set[v]!=set[u]&&match[u]!=v)

        {

            if(v==S||match[v]!=-1&&pre[match[v]]!=-1) contract(u,v);

            else if(pre[v]==-1)

            {

                pre[v]=u;

                if(match[v]!=-1)

                {

                    Q.push(match[v]);

                    inque[match[v]]=1;

                }

                else

                {

                    u=v;

                    while(u!=-1)

                    {

                        v=pre[u];

                        t=match[v];

                        match[u]=v;

                        match[v]=u;

                        u=t;

                    }

                    return 1;

                }

            }

        }

    }

    return 0;

}



int solve()

{

    SET(match,-1);

    int i,ans=0;

    for(i=1;i<=n;i++) if(match[i]==-1&&BFS(i)) ans++;

    return ans;

}



int dx[]={-1,-1,-1,1,1,1,0,0,2,-2,2,-2,2,-2,2,-2,1,-1,-1,1};

int dy[]={-1,1,0,0,1,-1,-1,1,2,2,-2,-2,1,-1,-1,1,2,-2,2,-2};

char str[20][20];

int R,C;

int num=0,Case;



int main()

{

    for(scanf("%d",&Case);Case--;)

    {

        scanf("%d%d",&R,&C);

        int i,j,k,x,y,kx,ky;

        SET(g,0);

        for(i=1;i<=R;i++) scanf("%s",str[i]+1);

        for(i=1;i<=R;i++) for(j=1;j<=C;j++) if(str[i][j]!='#')

        {

            for(k=0;k<20;k++)

            {

                x=i+dx[k];

                y=j+dy[k];

                if(x>=1&&x<=R&&y>=1&&y<=C&&str[x][y]!='#')

                {

                    g[(i-1)*C+j][(x-1)*C+y]=1;

                    g[(x-1)*C+y][(i-1)*C+j]=1;

                }

            }

            if(str[i][j]=='K') kx=i,ky=j;

        }

        n=R*C;

        int t1=solve();

        x=(kx-1)*C+ky;

        for(i=1;i<=n;i++) if(g[x][i]) g[x][i]=g[i][x]=0;

        printf("Case #%d: daizhenyang ",++num);

        if(solve()==t1) puts("lose");

        else puts("win");

    }

    return 0;

}

  

你可能感兴趣的:(HDU)