1. 程式人生 > 其它 >題解 UVA12083 【Guardian of Decency】

題解 UVA12083 【Guardian of Decency】

題目傳送門


題意簡述

老師帶學生出去旅遊,老師想要儘可能的避免學生談戀愛,又想盡可能的帶學生出去, 四種情況滿足任意種都不會談戀愛:

1.身高差超過40釐米

2.性別一樣

3.音樂風格不一樣

4.愛好的運動一樣

現在老師想知道他最多能帶多少學生。


演算法分析:二分圖最大獨立集

顯然,所有的學生可以被分為兩部分,可能會談戀愛的學生必須被放在不同的部分,並且在同一部分內的學生不可能談戀愛,這樣分開以後滿足了二分圖的定義。

現在我們對學生進行選擇。顯然,每一對可能談戀愛的學生只能選擇一個。我們考慮對每一對可能談戀愛的學生連一條邊,然後求二分圖最大獨立集

二分圖最大獨立集:簡單的說,就是“任意兩點間都沒有邊相連”的點集。

引理:

二分圖最大獨立集的大小等於點數 \(n\) 減去最大匹配數。

下面給出證明:

證明:

選出最多的點構成獨立集

\(\Leftrightarrow\) 刪去最少的點使剩下的點之間沒有邊

\(\Leftrightarrow\) 用最少的點覆蓋所有的邊(最小點覆蓋)

因此,二分圖最大獨立集等於點數 \(n\) 減去最小點覆蓋,剩餘的點構成最大獨立集。而最小點覆蓋等於最大匹配數。故最大獨立集的大小等於 \(n\) 減去最大匹配數。

得證。

——參考《演算法競賽進階指南》

(關於最小點覆蓋等於最大匹配數的證明,請看這篇部落格

綜上,跑一邊最大匹配即可。


下面給出大家喜聞樂見的程式碼:

#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

歡迎交流討論,請點個贊哦~