题解 UVA12083 【Guardian of Decency】

题目传送门


题意简述

老师带学生出去旅游,老师想要尽可能的避免学生谈恋爱,又想尽可能的带学生出去, 四种情况满足任意种都不会谈恋爱:

1.身高差超过40厘米

2.性别一样

3.音乐风格不一样

4.爱好的运动一样

现在老师想知道他最多能带多少学生。


算法分析:二分图最大独立集

显然,所有的学生可以被分为两部分,可能会谈恋爱的学生必须被放在不同的部分,并且在同一部分内的学生不可能谈恋爱,这样分开以后满足了二分图的定义。

现在我们对学生进行选择。显然,每一对可能谈恋爱的学生只能选择一个。我们考虑对每一对可能谈恋爱的学生连一条边,然后求二分图最大独立集

二分图最大独立集:简单的说,就是“任意两点间都没有边相连”的点集。

引理:

二分图最大独立集的大小等于点数 \(n\) 减去最大匹配数。

下面给出证明:

证明:

选出最多的点构成独立集

\(\Leftrightarrow\) 删去最少的点使剩下的点之间没有边

\(\Leftrightarrow\) 用最少的点覆盖所有的边(最小点覆盖)

因此,二分图最大独立集等于点数 \(n\) 减去最小点覆盖,剩余的点构成最大独立集。而最小点覆盖等于最大匹配数。故最大独立集的大小等于 \(n\) 减去最大匹配数。

得证。

——参考《算法竞赛进阶指南》

(关于最小点覆盖等于最大匹配数的证明,请看这篇博客

综上,跑一边最大匹配即可。


code:

#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<string>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
const int N=1e3+10;
int n,mch[N],T;
struct P{
	int high;
	char sex;
	string music,sport;
	inline void in(){
		cin>>high>>sex>>music>>sport;
		//身高,性别,音乐,运动 
	}
}a[N];
vector<int>f[N];
bool vis[N];
bool dfs(int x) { 
	for(int i=0; i<f[x].size(); i++) {
		int &pos=f[x][i];
		if(vis[pos])continue;
		vis[pos]=1;
		if(!mch[pos] or dfs(mch[pos])) {
			mch[pos]=x;
			return true;
		}
	}
	return false;
}
int main() {
	cin.tie(0);
	cin>>T;
	while(T--) {
		cin>>n;
		memset(mch,0,sizeof(mch));
		F(i,1,n)f[i].clear();//清空 
		F(i,1,n)a[i].in();
		F(i,1,n){
			F(j,1,n){
				if(i==j)continue;
				if(abs(a[i].high-a[j].high)>40)continue;//身高差距过大 
				if(a[i].sex==a[j].sex)continue;//性别相同 
				if(a[i].music!=a[j].music)continue;//喜欢的音乐不同 
				if(a[i].sport==a[j].sport)continue;//爱好的运动一样 
				f[i].push_back(j);
			}
		}
		int ans=0;
		F(i,1,n) {//匹配板子 
			memset(vis,0,sizeof(vis));
			ans+=dfs(i);
		}
		cout<<n-(ans>>1)<<endl;//最大独立集 
	}
	return 0;
}

AC

欢迎交流讨论,请点个赞哦~

posted @ 2021-06-23 16:07  Maplisky  阅读(46)  评论(0编辑  收藏  举报