1. 程式人生 > >2019.01.03-bzoj-1443-[JSOI2009]遊戲Game

2019.01.03-bzoj-1443-[JSOI2009]遊戲Game

題目描述:

演算法標籤:博弈,二分圖匹配

思路:

二分圖匹配每次是從一條匹配邊走向非匹配邊,對應到這題的博弈中,倘若先手在某一點上,後手走匹配邊,達到另一點,先手在走一條非匹配邊,表示恰好勢均力敵的狀態。此時倘若先手走一點匹配不到其他點,則這個點作為起點必然可以導致後手勝利。考慮一下還有沒有其他情況,從這些點反向往回走,每次間隔走的那些點,最後也會剩餘一個點沒有匹配點所以也是答案。

以下程式碼:

#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\n",ans); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++) if(v[i][j])printf("%d %d\n",i,j); return 0; }
View Code