hdu3446 daizhenyang's chess,一般图匹配

来源:互联网 发布:大学生java培训课程 编辑:程序博客网 时间:2024/05/19 20:59
hdu3446 daizhenyang's chess
一般图匹配问题。
将所有'.'的点之间可到达的建边。求最大匹配。

最后将K点加入,找增广路。
如果找到增广路,先手胜,否则后手胜。

证明比较容易(如果找到增广路,则先手可以找到一个包含偶数个点也就是奇数个边的路径,这样最后一次走的还是先手)。


#include<iostream>#include<cstdio>#include<cstring>#include<queue>using namespace std;#define Maxn 250int set[Maxn];int vis[Maxn],next[Maxn],mark[Maxn],spouse[Maxn];int q[Maxn*2],head,tail;int n;int tn,tm;int tlev=0;int di[]={-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,1,1,1,1,1,2,2,2,2};int dj[]={-2,-1,1,2,-2,-1,0,1,2,-1,1,-2,-1,0,1,2,-2,-1,1,2};int fi[Maxn],ne[Maxn*Maxn],to[Maxn*Maxn],te;void addedge(int u,int v){    //printf(" %d %d\n",u,v);    te++;ne[te]=fi[u];fi[u]=te;to[te]=v;}int findset(int x){return x==set[x]?x:set[x]=findset(set[x]);}void mergeset(int x,int y){x=findset(x);y=findset(y);if (x!=y) set[x]=y;}int findlca(int u,int v){    tlev++;    while(1){        if (u!=-1){            u=findset(u);            if (vis[u]==tlev) return u;            vis[u]=tlev;            if (spouse[u]!=-1) u=next[spouse[u]];            else u=-1;        }        swap(u,v);    }}void group(int a,int p){    int b,c;    while(a!=p){        b=spouse[a];c=next[b];        if (findset(c)!=p) next[c]=b;        if (mark[b]==2) mark[q[tail++]=b]=1;        if (mark[c]==2) mark[q[tail++]=c]=1;        mergeset(a,b);        mergeset(b,c);        a=c;    }}void findaugment(int s){    int i,j,k,l,e,u,v,p;    for(i=1;i<=n;++i){        next[i]=-1;set[i]=i;mark[i]=0;vis[i]=-1;    }    q[head=0]=s;tail=1;mark[s]=1;    while(head<tail){        if (spouse[s]!=-1) break;        u=q[head++];        for(e=fi[u];~e;e=ne[e]){            v=to[e];            if (spouse[u]!=v&&findset(u)!=findset(v)&&mark[v]!=2){                if (mark[v]==1){                    p=findlca(u,v);                    if (findset(u)!=p) next[u]=v;                    if (findset(v)!=p) next[v]=u;                    group(u,p);                    group(v,p);                }                else if (spouse[v]==-1){                    next[v]=u;                    for(j=v;j!=-1;){                        k=next[j];                        l=spouse[k];                        spouse[k]=j;spouse[j]=k;                        j=l;                    }                    break;                }                else{ //spouse[v]!=-1                    next[v]=u;                    mark[q[tail++]=spouse[v]]=1;                    mark[v]=2;                }            }        }    }}int work(){    int i,ret;    for(i=1;i<=n;++i) spouse[i]=-1;    for(i=1;i<=n;++i)if (spouse[i]==-1) findaugment(i);    ret=0;    for(i=1;i<=n;++i)        if (~spouse[i]) ret++;    return ret;}int abs(int x){return x<0?-x:x;}char s[20][20];int g[20][20];void makegraph(int i,int j,int func){    int d,vi,vj;    for(d=0;d<20;++d){        vi=i+di[d];        vj=j+dj[d];        if (vi<0||vi>=tn||vj<0||vj>=tm) continue;        if (g[vi][vj]==1) {            addedge(i*tm+j+1,vi*tm+vj+1);            if (func==2) addedge(vi*tm+vj+1,i*tm+j+1);        }    }}int main(){    int i,j,tcas,cas,sti,stj;    scanf("%d",&tcas);    for(cas=1;cas<=tcas;++cas){        scanf("%d%d",&tn,&tm);        n=tn*tm;        for(i=0;i<tn;++i){            scanf("%s",s[i]);        }        queue<int> qi,qj;        memset(g,0,sizeof(g));        for(i=0;i<tn;++i){            for(j=0;j<tm;++j){                if (s[i][j]=='K') {sti=i;stj=j;}                else if(s[i][j]=='.') {qi.push(i);qj.push(j);g[i][j]=1;}            }        }        memset(fi,-1,sizeof(fi));        te=0;        while(!qi.empty()){            i=qi.front();qi.pop();            j=qj.front();qj.pop();            makegraph(i,j,1);        }        work();        makegraph(sti,stj,2);        findaugment(sti*tm+stj+1);        printf("Case #%d: ",cas);        if (spouse[sti*tm+stj+1]!=-1){            printf("daizhenyang win\n");        }        else printf("daizhenyang lose\n");    }    return 0;}


0 0
原创粉丝点击