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

猜你喜欢

转载自www.cnblogs.com/Jessie-/p/10217831.html