HDU 3446 daizhenyang's chess

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");
	}
}
posted @ 2020-06-10 18:40  _xuefeng  阅读(163)  评论(7编辑  收藏  举报