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;
}


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