題解 UVA12083 【Guardian of Decency】
阿新 • • 發佈:2021-06-23
題意簡述
老師帶學生出去旅遊,老師想要儘可能的避免學生談戀愛,又想盡可能的帶學生出去, 四種情況滿足任意種都不會談戀愛:
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; }
歡迎交流討論,請點個贊哦~