题目描述:
算法标签:博弈,二分图匹配
思路:
二分图匹配每次是从一条匹配边走向非匹配边,对应到这题的博弈中,倘若先手在某一点上,后手走匹配边,达到另一点,先手在走一条非匹配边,表示恰好势均力敌的状态。此时倘若先手走一点匹配不到其他点,则这个点作为起点必然可以导致后手胜利。考虑一下还有没有其他情况,从这些点反向往回走,每次间隔走的那些点,最后也会剩余一个点没有匹配点所以也是答案。
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=105,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};char s[N][N]; int n,m,d[N][N],now,px[N][N],py[N][N];bool pd,v[N][N],ed[N][N]; il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;} il bool dfs(int x,int y){ d[x][y]=now; if(px[x][y]&&d[px[x][y]][py[x][y]]!=now)return dfs(px[x][y],py[x][y]); for(int i=0;i<4;i++){ int xx=x+dx[i],yy=y+dy[i]; if(!px[xx][yy]&&s[xx][yy]=='.'&&d[xx][yy]!=now){ px[xx][yy]=x;py[xx][yy]=y; px[x][y]=xx;py[x][y]=yy;return 1; } } for(int i=0;i<4;i++){ int xx=x+dx[i],yy=y+dy[i]; if(s[xx][yy]=='.'&&d[xx][yy]!=now&&dfs(xx,yy)){ px[xx][yy]=x;py[xx][yy]=y; px[x][y]=xx;py[x][y]=yy;return 1; } } return 0; } il void dfs2(int x,int y){ if(ed[x][y])return;v[x][y]=1;ed[x][y]=1; for(int i=0;i<4;i++){ int xx=dx[i]+x,yy=dy[i]+y; if(s[xx][yy]=='.'&&px[xx][yy])dfs2(px[xx][yy],py[xx][yy]); } } int main() { n=read();m=read(); 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++){ if(s[i][j]=='.'&&!px[i][j])now++,dfs(i,j); } } for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) if(!px[i][j]&&s[i][j]=='.')v[i][j]=1; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) if(!px[i][j]&&s[i][j]=='.')dfs2(i,j); int ans=0; for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) if(v[i][j])ans++; printf("%d ",ans); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) if(v[i][j])printf("%d %d ",i,j); return 0; }