hdu3446 daizhenyang's chess
一般图匹配问题。
将所有'.'的点之间可到达的建边。求最大匹配。
最后将K点加入,找增广路。
如果找到增广路,先手胜,否则后手胜。
证明比较容易(如果找到增广路,则先手可以找到一个包含偶数个点也就是奇数个边的路径,这样最后一次走的还是先手)。
一般图匹配问题。
将所有'.'的点之间可到达的建边。求最大匹配。
最后将K点加入,找增广路。
如果找到增广路,先手胜,否则后手胜。
证明比较容易(如果找到增广路,则先手可以找到一个包含偶数个点也就是奇数个边的路径,这样最后一次走的还是先手)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define Maxn 250
int 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;
}