HDU 1281(棋盘游戏)二分匹配+暴力

开始你不敢敲估计是怕暴力超时,其实不会的我直接暴力,安静只用了0ms。我也是醉了。

首先x,y轴的二分匹配,然后把跑出的最大匹配中的边删掉,再跑一遍二分匹配,如果这个结果和原来的不一样说明此点就是题目所说的重要点,然后再把删完的这条边再补回去,然后枚举每一个最大匹配的边。

不要惊讶,就这么简单尴尬

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=100+5;
int map[N][N],x[N*N],y[N*N],vis[N],link[N],link1[N];
int n,m,k;
bool dfs(int x)
{
	for(int i=1;i<=m;i++)
	{
		if(!vis[i]&&map[x][i])
		{
			vis[i]=1;
			if(link[i]==-1||dfs(link[i]))
			{
				link[i]=x;
				return true;
			}
		}
	}
	return false;
}
bool dfs1(int x)
{
	for(int i=1;i<=m;i++)
	{
		if(!vis[i]&&map[x][i])
		{
			vis[i]=1;
			if(link1[i]==-1||dfs(link1[i]))
			{
				link1[i]=x;
				return true;
			}
		}
	}
	return false;
}
int main()
{
	int t=1;
	while(~scanf("%d%d%d",&n,&m,&k))
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			{
				map[i][j]=0;
			}
		}
		memset(x,0,sizeof(x));
		memset(link,-1,sizeof(link));
		for(int i=1;i<=k;i++)
		{
			scanf("%d%d",&x[i],&y[i]);
			map[x[i]][y[i]]=1;
		}
		int res=0;
		for(int i=1;i<=n;i++)//第一遍二分匹配跑出最大匹配
		{
			if(!x[i]) continue;
			memset(vis,0,sizeof(vis));
			if(dfs(i))
			{
				res++;
			}
		}
		int ans=0;
		for(int i=1;i<=m;i++)//第二遍枚举最大二分匹配里面的边
		{
			int txt=0;
			if(link[i]!=-1)
			{
				map[link[i]][i]=0;//删除
				memset(link1,-1,sizeof(link1));
				for(int j=1;j<=n;j++)
		        {
			        if(!x[j]) continue;
			        memset(vis,0,sizeof(vis));
			        if(dfs1(j))
			        {
				        txt++;
			        }
		        }
		        if(txt!=res) ans++;
		        map[link[i]][i]=1;//切记一定要还原
			}
		}
		printf("Board %d have %d important blanks for %d chessmen.\n",t++,ans,res);
	}
	return 0;
} 

你可能感兴趣的:(二分匹配)