移动可以理解为空白格的移动,问题等价于双方在一张无向图(相邻不同色点连边,起点视为黑色)移动,不能经过重复的点,无法移动者为负
由于这张图是二分图,因此有结论,先手必胜当且仅当起点一定在任意一组最大匹配中
证明:
必要性,即先手必胜=>一定在匹配中,其等价于不在匹配中=>后手必胜,考虑一组最大匹配,容易发现先手所走到的点一定在最大匹配中(否则匹配可以增大),而后手的策略就是一直走到那个点的匹配上,一定必胜
充分性,即一定在匹配中=>先手必胜,那么当去掉起点后的最大匹配中,一定存在某一个点使得其可以不在剩下点的最大匹配中,即这个点后手必胜,那么先手走到这个点即可
具体实现就是说先将其他节点的最大匹配求出,然后再加入这个节点判断能否增大,每一步都只需要重新判断新的空格即可
(其实这个东西就是说让答案+1即存在一条增广路,而增广路一定是奇数条边,所以差不多就是这样了)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2005 4 struct ji{ 5 int nex,to; 6 }edge[N<<3]; 7 int E,n,m,k,x,y,dx[4]={-1,0,0,1},dy[4]={0,-1,1,0},a[N],vis[N],ans[N],mat[N],head[N]; 8 char s[105][105]; 9 int id(int x,int y){ 10 return x*m+y+1; 11 } 12 void add(int x,int y){ 13 edge[E].nex=head[x]; 14 edge[E].to=y; 15 head[x]=E++; 16 if (E&1)add(y,x); 17 } 18 int dfs(int k){ 19 if ((k<0)||(vis[k]))return 0; 20 vis[k]=1; 21 for(int i=head[k];i!=-1;i=edge[i].nex){ 22 int v=edge[i].to; 23 if ((!mat[v])||(dfs(mat[v]))){ 24 mat[v]=k; 25 mat[k]=v; 26 return 1; 27 } 28 } 29 return 0; 30 } 31 int main(){ 32 scanf("%d%d",&n,&m); 33 for(int i=0;i<n;i++)scanf("%s",s[i]); 34 memset(head,-1,sizeof(head)); 35 for(int i=0;i<n;i++) 36 for(int j=0;j<m;j++) 37 if (s[i][j]!=‘O‘) 38 for(int k=0;k<4;k++){ 39 x=i+dx[k]; 40 y=j+dy[k]; 41 if ((x>=0)&&(y>=0)&&(x<n)&&(y<m)&&(s[x][y]==‘O‘))add(id(i,j),id(x,y)); 42 } 43 for(int i=0;i<n;i++) 44 for(int j=0;j<m;j++){ 45 if (s[i][j]==‘.‘){ 46 x=i+1; 47 y=j+1; 48 } 49 if (s[i][j]!=‘O‘){ 50 memset(vis,0,sizeof(vis)); 51 dfs(id(i,j)); 52 } 53 } 54 scanf("%d",&k); 55 for(int i=0;i<(k<<1);i++){ 56 if (i)scanf("%d%d",&x,&y); 57 int z=mat[id(--x,--y)]; 58 mat[id(x,y)]=-1; 59 if (z>0){ 60 mat[z]=0; 61 memset(vis,0,sizeof(vis)); 62 a[i]=(!dfs(z)); 63 } 64 if ((i&1)&&(a[i-1])&&(a[i]))ans[++ans[0]]=i/2+1; 65 } 66 for(int i=0;i<=ans[0];i++)printf("%d\n",ans[i]); 67 }
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11818028.html
时间: 2024-10-18 21:26:19