zoukankan      html  css  js  c++  java
  • 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;
    }
        
    	    
    
  • 相关阅读:
    Vue 错误:Avoid mutating a prop directly
    插入排序
    Vue2.0实现ie的兼容
    mysql8.0遇到删除外键的错误
    c# 根据父节点id,找到所有的子节点数据
    SSH原理与运用(一):远程登录
    Java线程:Timer和TimerTask
    linux系统判断是否重启、关机、查询登录诊断分析简介
    CS架构和BS架构的区别
    yum提示another app is currently holding the yum lock;waiting for it to exit
  • 原文地址:https://www.cnblogs.com/Alseo_Roplyer/p/10219177.html
Copyright © 2011-2022 走看看