acdream 1403 Graph Game 二分匹配

传送门:acdream 1403

        给定一张二分图,现在有一场博弈,给一个点定一个标记,然后每次操作把标记移动到某个相邻的点上面,然后把原点以及所有相邻的边都剔除,无法移动的人判输。现在需要你判断所有点为起点时,先手必输还是必胜。

         

        战斗名族的题果然不一样,ASC做的时候就是想不到,就是简单的二分匹配,然后判断每个点剔除之后最大匹配是否会减少,若减少了则说明该点是二分匹配的关键点,剔除之后导致无法移动回原集团,即最终移动步数为奇数,因此先手胜,否则无论怎么动都能移动回来,即先手输

/******************************************************
 * File Name:   1403.cpp
 * Author:      kojimai
 * Creater Time:2014年10月03日 星期五 10时40分32秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
#define FFF 505
int linkx[FFF],linky[FFF],n1,n2;
vector<int> p[2][FFF];
bool ans1[FFF],ans2[FFF],visx[FFF],visy[FFF];
bool dfs(int x)
{
//	cout<<"x="<<x<<endl;
	for(int i = 0;i < p[0][x].size(); i++)
	{
		int v = p[0][x][i];
		if(!visy[v])
		{
//			cout<<" v="<<v<<" link="<<linky[v]<<endl;
			visy[v] = true;
			if(linky[v]==-1 || dfs(linky[v]))
			{
				linkx[x] = v;
				linky[v] = x;
				return true;
			}
		}
	}
	return false;
}
bool dfs2(int y)
{
	for(int i = 0;i < p[1][y].size();i++)
	{
		int v = p[1][y][i];
		if(!visx[v])
		{
			visx[v] = true;
			if(linkx[v] == -1 || dfs2(linkx[v]))
			{
				linkx[v] = y;
				linky[y] = v;
				return true;
			}
		}
	}
	return false;
}
void out()
{
	for(int i =1;i <= 3;i++)
	{
		cout<<"i="<<i<<" linkx[i]="<<linkx[i]<<endl;
		cout<<"i="<<i<<" linky[i]="<<linky[i]<<endl;
	}
}
int main()
{
	int m,x,y;
	scanf("%d%d%d",&n1,&n2,&m);
	for(int i = 0;i < m; i++)
	{
		scanf("%d%d",&x,&y);
		p[0][x].push_back(y);
		p[1][y].push_back(x);
	}
	memset(linkx,-1,sizeof(linkx));
	memset(linky,-1,sizeof(linky));
	for(int i = 1;i <= n1; i++)
	{
		if(linkx[i] == -1)
		{
			memset(visy,false,sizeof(visy));
			dfs(i);
		}
	}//先找出可能的最大匹配
	//out();
	memset(ans1,false,sizeof(ans1));
	memset(ans2,false,sizeof(ans2));
	for(int i = 1;i <= n1; i++)//起点为左边集团的点时,先剔除该点然后看最大匹配是否减少
	{
		if(linkx[i] == -1)
			continue;
		else{
			memset(visx,false,sizeof(visx));
			visx[i] = true;
			if(!dfs2(linkx[i]))
			{
				ans1[i] = true;//若最大匹配减少了,即剔除该点之后无法构成新的最大匹配
			}
			else
				linkx[i] = -1;//若能构成最大匹配则要把原来的边剔除
		}
	}
	//out();
	for(int i = 1;i <= n2; i++)//起点为右边集团的点时,同上
	{
		if(linky[i] == -1)
			continue;
		else  {
			memset(visy,false,sizeof(visy));
			visy[i] = true;
			if(!dfs(linky[i]))
				ans2[i] = true;
			else
				linky[i] = -1;
		}
	}
	//out();
	for(int i = 1;i <= n1;i++)
	{
		if(ans1[i])
			cout<<'N';
		else
			cout<<'P';
	}
	cout<<endl;
	for(int i = 1;i <= n2;i++)
	{
		if(ans2[i])
			cout<<'N';
		else
			cout<<'P';
	}
	cout<<endl;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章