转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:给出一个n*m的格子。有一些障碍物。两人轮流,第一个人先选定某个位置,后一个人只能在前一个人选的位置相邻的位置。不能移动者输。不能选择已经选过的位置 。
同样还是2012年lartin america的题。。。
第一次接触这种博弈。
大致做法是这样的:
对于某一个连通块,当第一个选定位置之后,根据相邻的染色
可以发现把所有的位置染成两种颜色,可以构建二分图。
如果这个二分图存在完备匹配的话,也就是先手随便在哪下,后手总能找到与其匹配的位置。
那么后手必胜。
这样以来就是判断所有的连通块是否存在完备匹配。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #define N 1255 #define pb(a) push_back(a) #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; struct Node{ int v,next; }e[100005]; vector<int>v[N]; int n,m; int tot,start[N]; int flag[55][55]; char str[55][55]; int w,b; int way[4][2]={0,1,0,-1,1,0,-1,0}; int pre[N]; bool mark[N]; void add(int u,int v){ e[tot].v=v; e[tot].next=start[u]; start[u]=tot++; } bool dfs_2(int i){ int j; for(j=start[i];j!=-1;j=e[j].next){ int k=e[j].v; if(!mark[k]){ mark[k]=true; if(pre[k]==0||dfs_2(pre[k])){ pre[k]=i; return true; } } } return false; } int match() { int i,count=0; memset(pre,0,sizeof(pre)); for(i=1;i<=w;i++){ mem(mark,false); if(dfs_2(i)) count++; } return count==w; } void dfs(int x,int y,int c,int u){ for(int i=0;i<4;i++){ int xx=x+way[i][0]; int yy=y+way[i][1]; if(xx<0||yy<0||xx>=n||yy>=m||str[xx][yy]=='X') continue; if(c==0){ if(flag[xx][yy]){ add(u,flag[xx][yy]); continue; } flag[xx][yy]=b; add(u,b); dfs(xx,yy,1,b++); } else{ if(flag[xx][yy]) continue; flag[xx][yy]=w; dfs(xx,yy,0,w++); } } } bool slove(int x,int y){ w=2;b=1; mem(start,-1); tot=0; flag[x][y]=1; dfs(x,y,0,1); w--;b--; if(w!=b) return false; return match(); } int main(){ while(scanf("%d%d",&n,&m)!=EOF){ mem(flag,0); for(int i=0;i<n;i++) scanf("%s",str[i]); bool ans=true; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ if(str[i][j]=='X'||flag[i][j]) continue; if(!slove(i,j)) ans=false; } } printf("%d\n",ans?2:1); } return 0; }
作者:ACM_cxlove 发表于2013-3-16 23:33:58 原文链接
阅读:47 评论:0 查看评论