hdu3446 daizhenyang's chess 【一般图匹配】

来源:互联网 发布:换字体软件 编辑:程序博客网 时间:2024/05/09 14:24

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

题意:在一个R行C列的棋盘上,俩个人轮流移动一个棋子,每次可以向相邻的20个格子移动,走过的每个格子自能走一次。另外,某些各自一开始就固定了不能走。  无法移动者输。问:先手能否赢。 

分析:首先,忽略K点,将其他能相互移动的格子连边,求一次最大匹配,再将K点加入图中,若存在增广路,则先手赢,否则后手赢。

代码:

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<string>#include<vector>#include<queue>#include<cmath>#include<stack>#include<set>#include<map>#define INF 0x3f3f3f3f#define Mn 400#define Mm 20005#define mod 1000000007#define CLR(a,b) memset((a),(b),sizeof((a)))#define CPY(a,b) memcpy ((a), (b), sizeof((a)))#pragma comment(linker, "/STACK:102400000,102400000")#define ul u<<1#define ur (u<<1)|1using namespace std;typedef long long ll;struct edge {    int v,next;}e[Mm];int tot,head[Mn];void addedge(int u,int v) {    e[tot].v=v;    e[tot].next=head[u];    head[u]=tot++;}int cnt,pre[Mn];int findpre(int x) {    return x==pre[x]?pre[x]:pre[x]=findpre(pre[pre[x]]);}void ol(int a,int b) {    a=findpre(a);    b=findpre(b);    if(a!=b) pre[a]=b;}int lk[Mn],vis[Mn],mark[Mn],match[Mn],ne[Mn];int lca(int x,int y) {    static int t=0;t++;    while(1) {        if(x!=-1) {            x=findpre(x);            if(vis[x]==t) return x;            vis[x]=t;            if(match[x]!=-1) x=ne[match[x]];            else x=-1;        }        swap(x,y);    }}queue<int> q;void group(int a,int p) {    while(a!=p) {        int b=match[a],c=ne[b];        if(findpre(c)!=p) ne[c]=b;        if(mark[b]==2) mark[b]=1,q.push(b);        if(mark[c]==2) mark[c]=1,q.push(c);        ol(a,b),ol(b,c);        a=c;    }}void aug(int s) {    for(int i=0;i<=cnt;i++) {        ne[i]=-1;        pre[i]=i;        mark[i]=0;        vis[i]=-1;    }    mark[s]=1;    while(!q.empty()) q.pop();    q.push(s);    while((!q.empty())&&match[s]==-1) {        int u=q.front();        q.pop();        for(int i=head[u];~i;i=e[i].next) {            int v=e[i].v;            if(match[u]==v||findpre(u)==findpre(v)||mark[v]==2) continue;            if(mark[v]==1) {                int r=lca(u,v);                if(findpre(u)!=r) ne[u]=v;                if(findpre(v)!=r) ne[v]=u;                group(u,r);                group(v,r);            } else if(match[v]==-1) {                ne[v]=u;                for(int x=v;~x;) {                    int y=ne[x];                    int mv=match[y];                    match[x]=y,match[y]=x;                    x=mv;                }                break;            } else {                ne[v]=u;                q.push(match[v]);                mark[match[v]]=1;                mark[v]=2;            }        }    }}int mp[Mn][Mn],num[Mn][Mn];void init() {    tot=0;cnt=0;    CLR(mp,0);    CLR(head,-1);    CLR(num,0);}int way[20][2]={-2,-2,-2,-1,-2,1,-2,2,-1,-2,-1,-1,-1,0,-1,1,-1,2,0,-1,0,1,1,-2,1,-1,1,0,1,1,1,2,2,-2,2,-1,2,1,2,2};int main() {    int t,n,m,kx,ky;    char s[Mn];    scanf("%d",&t);    for(int cas=1;cas<=t;cas++) {        scanf("%d%d",&n,&m);        init();        for(int i=0;i<n;i++) {            scanf("%s",s);            for(int j=0;j<m;j++) {                if(s[j]=='K') {                    kx=i,ky=j;                }                if(s[j]!='#') {                    num[i][j]=++cnt;                }            }        }        for(int i=0;i<n;i++) {            for(int j=0;j<m;j++) {                if(!num[i][j]||(i==kx&&j==ky)) continue;                for(int k=0;k<20;k++) {                    int x=i+way[k][0];                    int y=j+way[k][1];                    if(x<0||x>=n||y<0||y>=m||(x==kx&&y==ky)||!num[x][y]) continue;                    int u=num[i][j],v=num[x][y];                    if(!mp[u][v]) {                        addedge(u,v);                        addedge(v,u);                        mp[u][v]=mp[v][u]=1;                    }                }            }        }        for(int i=1;i<=cnt;i++) match[i]=-1;        for(int i=1;i<=cnt;i++) {            if(match[i]==-1) {                aug(i);            }        }        for(int k=0;k<20;k++) {            int x=kx+way[k][0];            int y=ky+way[k][1];            if(x<0||x>=n||y<0||y>=m||!num[x][y]) continue;            int u=num[kx][ky],v=num[x][y];            addedge(u,v);            addedge(v,u);        }        aug(num[kx][ky]);        printf("Case #%d: ",cas);        if(match[num[kx][ky]]==-1) printf("daizhenyang lose\n");        else printf("daizhenyang win\n");    }    return 0;}


0 0
原创粉丝点击