http://acm.hdu.edu.cn/showproblem.php?pid=3446
题意
一个棋盘,有个KING,有一些能走的点,每次只能走到没走过的地方,没路可走的输,求先手是否必胜。
题解
一般图最大匹配,判断KING是否一定在最大匹配中,在的话一定先手必胜.
判断KING一定在最大匹配的方法就是加入KING跑最大匹配,然后不加入KING再跑一次最大匹配看最大匹配数量是否改变.
在最大匹配一定先手必胜原因:
如果KING在最大匹配,那么先手每次都走匹配边,后手就只能走非匹配边,而后手走到的点一定是匹配点
此刻只需要让先手一直走匹配边,就可以必胜了.
非匹配边走到的点一定是匹配点的原因:
假如这个点没有匹配,那么可以将之前所有经过的路径匹配边变成非匹配边,非匹配边变成匹配边,那么此时的匹配个数并没有发生改变
而KING变成了非匹配点,不符合KING在最大匹配的前提
KING一定变成了非匹配点的原因:
因为原匹配是最大匹配,而翻转边后匹配个数不变,如果KING变成了匹配点就增加了一个匹配,不符合原匹配是最大匹配的前提
不在最大匹配一定先手必败的原因:
如果KING不在最大匹配,那么一定存在一种情况满足KING是非匹配点,此时先手无论怎么走走到的都是匹配点,那对手就每次都可以走匹配边,就可以必胜了.
非匹配点走到的点一定是匹配点的原因:
假如这个
我被教育了
假如非匹配点走到的点是非匹配点,不就能匹配了吗
#include<bits/stdc++.h>
#define id(x,y) ((x-1)*m+y)
using namespace std;
const int N=20;
inline int rd(register int x=0,register char ch=getchar(),register int f=0){
for(;!isdigit(ch);ch=getchar()) f=ch=='-';
for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-48;
return f?-x:x;
}
int n,m;
int match[N*N],vis[N*N];
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 s[N][N];
vector<int> e[N*N];
bool check(int x,int y){
return (x<=0||x>n||y<=0||y>m||s[x][y]!='.')?0:1;
}
void lnk(int x,int y){
e[x].push_back(y),e[y].push_back(x);
}
int dfs(int x){
vis[x]=1;
random_shuffle(e[x].begin(),e[x].end());
for(auto to:e[x]) if(!match[to]) return vis[to]=1,match[to]=x,match[x]=to,1;
for(auto to:e[x]){
int y=match[to];
if(vis[y]) continue;
match[x]=to,match[to]=x,match[y]=0;
if(dfs(y)) return 1;
match[x]=0,match[to]=y,match[y]=to;
}
return 0;
}
int main(){
srand((unsigned)time(0));
for(int T=rd(),o=1;o<=T;++o){
n=rd();m=rd();
for(int i=1;i<=n;++i) scanf("%s",s[i]+1);
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) e[id(i,j)].clear();
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(s[i][j]=='.') for(int k=0;k<20;++k) if(check(i+dx[k],j+dy[k])) lnk(id(i,j),id(i+dx[k],j+dy[k]));
int ans=0,tim=0;
memset(match,0,sizeof match);
while(++tim<3) for(int i=1;i<=n*m;++i) if(!match[i]) memset(vis,0,sizeof vis),ans+=dfs(i);
int nans=0,ntim=0;
memset(match,0,sizeof match);
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(s[i][j]=='K') for(int k=0;k<20;++k) if(check(i+dx[k],j+dy[k])) lnk(id(i,j),id(i+dx[k],j+dy[k]));
while(++ntim<3) for(int i=1;i<=n*m;++i) if(!match[i]) memset(vis,0,sizeof vis),nans+=dfs(i);
printf("Case #%d: ",o);
puts(ans==nans?"daizhenyang lose":"daizhenyang win");
}
}