题解 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;
}
欢迎交流讨论,请点个赞哦~
本文来自博客园,作者:Maplisky,转载请注明原文链接:https://www.cnblogs.com/lbh2021/p/14920572.html