Warm up 2 HDU - 4619 二分图 匈牙利算法

题目链接:HDU-4619

主要思路:

首先,先看懂题目(表示由于英语问题给题目卡了很久)。最终合法情况是棋盘上没有相互覆盖的骨牌。其中方向相同的不会覆盖是题目输入数据的条件。

我们对每个点进行分析,每个点只能和他周围的四个点构成一个骨牌(当然这个骨牌要存在)。故在一个骨牌中两个点为一个配对,而一个棋盘内有两种点(相邻的两个点不同种),每条边都由其中一种点指向另一种点,最后算最大匹配即可。

下为图中点的分类例子:

1 0 1

0 1 0

1 0 1

AC代码:

#include<cstdio>
#include<vector>
#include<cstring>
#define M 10005
using namespace std;
vector<int>way[M];
int chose[M];
bool used[M];
bool find(int now){//匈牙利算法 
	for(int i=0;i<way[now].size();i++){
		int nxt=way[now][i];
		if(!used[nxt]){
			used[nxt]=1;
			if(!chose[nxt]||find(chose[nxt])){
				chose[nxt]=now;
				return 1;
			}
		}
	}
	return 0;
}
int mp[105][105],id;
bool Kind[M];
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		memset(chose,0,sizeof(chose));
		for(int i=1;i<=id;i++)way[i].clear();
		memset(mp,0,sizeof(mp));//mp存点的序号 
		id=0;
		if(!n&&!m)return 0;
		for(int i=1;i<=n;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			if(!mp[x][y]){
				mp[x][y]=++id;
				if((x+y)%2)Kind[id]=0;//第0种  这样子分类相邻两个点肯定不属于同一种点 
				else Kind[id]=1;//第1种 这样就可以将点分成一个二分图 
			}
			if(!mp[x+1][y]){
				mp[x+1][y]=++id;
				if((x+y+1)%2)Kind[id]=0;
				else Kind[id]=1;
			}
			int u=mp[x][y],v=mp[x+1][y];
			if(Kind[u]==1)way[u].push_back(v);//由一种点连向另一种点 
			else way[v].push_back(u);
		}
		for(int i=1;i<=m;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			if(!mp[x][y]){
				mp[x][y]=++id;
				if((x+y)%2)Kind[id]=0;
				else Kind[id]=1;
			}
			if(!mp[x][y+1]){
				mp[x][y+1]=++id;
				if((x+y+1)%2)Kind[id]=0;
				else Kind[id]=1;
			}
			int u=mp[x][y],v=mp[x][y+1];
			if(Kind[u]==1)way[u].push_back(v);
			else way[v].push_back(u);
		}
		int ans=0;
		for(int i=1;i<=id;i++){
			memset(used,0,sizeof(used));
			if(Kind[i]&&find(i))ans++;//找最大匹配 
		}
		printf("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35320178/article/details/81506765