題意:有n個點心,m個客人,每個客人有兩個喜歡的點心,現需要給客人安排一定順序,每輪到一個人,他喫掉所有剩下的他喜歡的點心(有一個喫一個,有倆喫倆)。一個都喫不到的人就會傷心。請問合理安排後最小的傷心人數是多少。
題解:我們需要儘可能平均分配,就讓每個人儘可能只吃一個(可以理解爲重複利用一些點心?A吃了1,2,B吃了2,3相當於2利用了兩次)。於是靈光乍現想到把每個客人看成一條邊然後跑個最長路之類的東西?後來細想一下發現不對,如果這麼建圖,一個人會傷心當且僅當這條邊兩端已經被連通過,所以應該用並查集來搞。於是直接跑一個並查集,merge的時候如果兩個點已經在同一個連通圖則ans++,就完了。
感覺這種建圖還是相當創新的一波操作,能做到這樣的題也算是意外收穫₍ ᐢ. ̫ .ᐢ ₎
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+4;
int n,m;
int fa[N];
int ans;
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline int find(int x) {
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void merge(int u,int v) {
int fu=find(u),fv=find(v);
if (fu^fv) {
fa[fu]=fv;
} else ++ans;
}
int main() {
n=read(),m=read();
for (register int i=1;i<=n;++i) fa[i]=i;
for (register int i=0;i<m;++i) {
int u=read(),v=read();
merge(u,v);
}
cout<<ans<<endl;
return 0;
}