• Bzoj_1443 [JSOI2009]游戏Game


    题意
    这是一个在n*m的网格图上的博弈。后手先选择一个网格,把棋子放上去,之后轮流操作棋子向相邻的格子移动,每个格子只能让棋子停留一次,同时图中存在一些障碍点。问后手能否赢,若能,问放在哪些格子上能赢。
    (1 leqslant n,m leqslant 100)

    题解
    一道博弈二分图匹配题。
    首先对网格图黑白染色,然后相邻格子之间连边跑最大匹配。如果存在完美匹配,那么后手必定输。因为不管棋子放在哪,先手必定沿着匹配边走,然后后手必定沿着非匹配边走,而每个点都被匹配了,那么后手一定将棋子移到一个匹配点上(或者不能移便输了),先手再沿匹配边走,重复这个过程后手便没有胜算。
    而一旦存在非匹配点,那么后手胜。因为只要先把棋子先放在一个非匹配点上,先手一定移动到匹配点上(否则两点直接匹配了),然后后手沿着匹配边走,先手又会移动到一个匹配点上(否则这个路径就是匈牙利算法的一个拓展路径,两个非匹配点就可以匹配上了),重复这个过程就行。
    然后第二问就是问哪些点不一定要在最大匹配中,我们暂时将其称为非关键点。显然非匹配点不一定要在最大匹配中。然后我们先选择一个非关键点,那么与它相连的点匹配的点,一定也是非关键点,因为最开始选择的那个点可以匹配掉与它们相邻的点,使得它们变成非匹配点,之后直接顺势递归下去即可。

    #include<cmath>
    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int dx[4]={0,0,1,-1};
    const int dy[4]={1,-1,0,0};
    const int maxn=100;
    int n,m,Time;
    int vis[maxn+8][maxn+8];
    bool can[maxn+8][maxn+8];
    char map[maxn+8][maxn+8];
    
    int read()
    {
        int x=0,f=1;char ch=getchar();
        for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
        for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
    
    struct pos
    {
        int x,y;
    }match[maxn+8][maxn+8];
    
    bool in_map(int x,int y){return x>=1&&x<=n&&y>=1&&y<=m&&map[x][y]=='.';}
    bool extra(int x,int y)
    {
        for (int i=0;i<4;i++)
    	{
    	    int sx=x+dx[i],sy=y+dy[i];
    	    if (!in_map(sx,sy)) continue;
    	    if (vis[sx][sy]==Time) continue;
    	    vis[sx][sy]=Time;
    	    if ((match[sx][sy].x==0)||extra(match[sx][sy].x,match[sx][sy].y))
    		{
    		    match[sx][sy]=(pos){x,y};
    		    match[x][y]=(pos){sx,sy};
    		    return 1;
    		}
    	}
        return 0;
    }
    
    void dfs(int x,int y)
    {
        if (can[x][y]) return;
        can[x][y]=1;
        for (int i=0;i<4;i++)
    	{
    	    int sx=x+dx[i],sy=y+dy[i];
    	    if (!in_map(sx,sy)) continue;
    	    dfs(match[sx][sy].x,match[sx][sy].y);
    	}
    }
    
    int main()
    {
        n=read(),m=read();
        for (int i=1;i<=n;i++) scanf("%s",map[i]+1);
        for (int i=1;i<=n;i++)
    	for (int j=1;j<=m;j++)
    	    if ((i+j)&1)
    		{
    		    Time++;
    		    if (map[i][j]=='#') continue;
    		    extra(i,j);
    		}
        bool flag=0;
        Time++;
        for (int i=1;i<=n;i++)
    	for (int j=1;j<=m;j++)
    	{
    	    if ((i+j)&1) continue;
    	    if (match[i][j].x) continue;
    	    if (map[i][j]=='#') continue;
    	    flag=1;
    	    dfs(i,j);
    	}
        for (int i=1;i<=n;i++)
    	for (int j=1;j<=m;j++)
    	    if ((i+j)&1)
    		{
    		    if (match[i][j].x) continue;
    		    if (map[i][j]=='#') continue;
    		    //printf("check:%d %d
    ",i,j);
    		    flag=1;
    		    dfs(i,j);
    		}
        if (!flag) puts("LOSE");
        else
    	{
    	    puts("WIN");
    	    for (int i=1;i<=n;i++)
    		for (int j=1;j<=m;j++)
    		    if (can[i][j])
    			printf("%d %d
    ",i,j);
    	}
        return 0;
    }
        
    	    
    
  • 相关阅读:
    国产CPU研究单位及现状
    大型网站用什么技术比较好,JSP,PHP,ASP.NET
    韩国企业百强排行榜!
    中国操作系统
    Visual C++2010开发权威指南 中文高清PDF
    printf以及各种变种
    SPDY以及HTTP2.0
    数字证书认证这点事, SSL/TLS,OpenSSL
    利用Fiddler,解密wireshark抓的HTTPS包
    C跟C++
  • 原文地址:https://www.cnblogs.com/Alseo_Roplyer/p/10219177.html
Copyright © 2020-2023  润新知