• NOI模拟赛(3.8)Problem B


    Description

    Alice和Bob在玩一个游戏,给出一张n*m的棋盘,上面有一些点是障碍,游戏的开始,Alice选定棋盘上任意一个不是障碍的格子,并且将一枚棋子放在其中,然后Bob先手,两人轮流操作棋子,每次操作必须将棋子从当前位置移动到一个相邻的无障碍且未经过的格子(即每个格子不允许经过两次),不能操作的人输,如果两人都按照最有策略操作,请问初始时Alice将棋子放在哪些格子上有必胜策略。
     

    Input

    第一行,两个正整数n,m
    接下来输入一个n*m字符矩阵,n行m列,’.’表示空的格子,‘#’表示有障碍的格子。

    Output

    第一行,一个正整数ans,为Alice有必胜策略的格子的个数。
    接下来ans行,每行一个坐标(x,y)表示第x行第y列是一个Alice有必胜策略的初始位置,以矩阵的左上角为(1,1),右下角为(n,m)。输出位置时按照x从小到大,当x相同时y从小到大的顺序输出。
     

    Sample Input

    2 2
    #.
    ..

    Sample Output

    2
    1 2
    2 1
     

    Data Constraint

    20%的数据: 1<=n,m<=4。
    60%的数据: 1<=n,m<=10
    100%的数据:1<=n,m<=100
     

    Hint

    如果Alice将棋子放在(1,2),Bob只能将其移动到(2,2),Alice再移动到(2,1),此时Bob无法移动,Alice获胜
    如果Alice将棋子放在(2,1)号点,类似以上情况
    如果Alice将棋子放在(2,2),Bob可以将棋子任意移动到(1,2)或(2,1),此时Bob获胜

    Solution

    由于是博弈论,可以转化成求二分图的关键点,即必然在二分图匹配中出现的点

    算法要考虑染色,即当前点染黑,周围点染白,染色后把连通块都用算法匹配掉

    若Alice走不在最大匹配点集内的点,则该点的周围连的一定都是匹配点,可知Bob一定走一条非匹配边到一个匹配点

    由于只要先选了最大匹配点就必胜,因此在这个条件下Alice必胜

    最后统计一下答案就好了

    #include <stdio.h>
    #include <string.h>
    
    template<class T> inline void read(T &x)
    	{
    	int c=getchar();bool b=0;
    	for(x=0;c<48||c>57;c=getchar())if(c==45)b=1;
    	for(;c>47&&c<58;c=getchar())x=(x<<1)+(x<<3)+c-48;
    	if(b)x=-x;
    	}
    
    const int N=200;
    bool win[N*N];
    int color[N*N],n,m,lab,num[N][N],vind,vis[N*N],lnk[N*N],Ans,fir[N*N],et=-1;
    char mat[N][N];
    
    struct Position
    	{
    	int x,y;
    	}pos[N*N];
    
    struct Pointer
    	{
    	int v,next;
    	}e[N*N*5];
    
    inline void link(int x,int y)
    	{
    	e[++et]=(Pointer){y,fir[x]},fir[x]=et;
    	e[++et]=(Pointer){x,fir[y]},fir[y]=et;
    	}
    
    bool dfs(int at)
    	{
    	for(int j=fir[at];~j;j=e[j].next)
    		if(vis[e[j].v]!=vind)
    			{
    			vis[e[j].v]=vind;
    			if((!lnk[e[j].v]) || dfs(lnk[e[j].v]))
    				{
    				lnk[e[j].v]=at;
    				return 1;
    				}
    			}
    	return 0;
    	}
    
    void find(int at)
    	{
    	for(int j=fir[at];~j;j=e[j].next)
    		if(lnk[e[j].v] && (!win[lnk[e[j].v]]))
    			{
    			win[lnk[e[j].v]]=1;
    			find(lnk[e[j].v]);
    			}
    	}
    
    int main()
    	{
    	memset(fir,-1,sizeof fir);
    	read(n),read(m);
    	for(int i=1;i<=n;i++)
    		scanf("%s",mat[i]+1);
    	lab=0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(mat[i][j]=='.')
    				{
    				num[i][j]=++lab;
    				pos[lab].x=i;
    				pos[lab].y=j;
    				color[lab]=((i+j)&1);
    				if(i>1 && mat[i-1][j]=='.')
    					link(lab,num[i-1][j]);
    				if(j>1 && mat[i][j-1]=='.')
    					link(lab,num[i][j-1]);
    				}
    	for(int i=1;i<=lab;i++)
    		if(!color[i])
    			{
    			++vind;
    			dfs(i);
    			}
    	for(int i=1;i<=lab;i++)
    		if(color[i]&&lnk[i])
    			lnk[lnk[i]]=i;
    	for(int i=1;i<=lab;i++)
    		if(!lnk[i])
    			{
    			win[i]=1;
    			find(i);
    			}
    	Ans=0;
    	for(int i=1;i<=lab;i++)
    		Ans+=win[i];
    	printf("%d
    ",Ans);
    	for(int i=1;i<=lab;i++)
    		if(win[i])
    			printf("%d %d
    ",pos[i].x,pos[i].y);
    	return 0;
    	}
    

      

  • 相关阅读:
    [整理] jQuery插件开发
    windows2008r2安装笔记
    javascript 中 typeof 和 instanceof 的区别
    mysql 复制表结构和表数据
    一个例子明白 javascript 中 for 与 for in 的区别
    实现自己的框架
    Jenkins 前端项目构建报错:Vue packages version mismatch
    linux Auditd 审计工具安装报错
    linux定时压缩日志文件脚本
    Robot Framework 3.1.2 执行测试用例报错
  • 原文地址:https://www.cnblogs.com/keshuqi/p/6527978.html
Copyright © 2020-2023  润新知