题目描述
Description
老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议。所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近。
输入描述
Input Description
第一行,三个正整数N,M,K。
第2...K行,每行2个数,表示一对实力相当的人的编号(编号为1…N)。
输出描述
Output Description
一行,表示既不让同学们抗议,又与原来的M尽可能接近的选出学霸的数目。(如果有两种方案与M的差的绝对值相等,选较小的一种。)
样例输入
Sample Input
4 3 2
1 2
3 4
样例输出
Sample Output
2
数据范围及提示
Data Size & Hint
100%的数据N,P<=30000
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
/* 由于实力相当的人不一定只有两个,所以先用并查集处理一下,统计每一组的人数, 我们可以把每组同学看成一个物品,人数就是体积,这样就成了一个背包问题了。 */ #include<cstdio> #include<cstdlib> #include<iostream> #define M 30010 using namespace std; int fa[M],n,m,p; int v[M],belong[M],f[M],cnt; int find(int x) { if(fa[x]==x)return x; return fa[x]=find(fa[x]); } int main() { scanf("%d%d%d",&n,&m,&p); for(int i=1;i<=n;i++)fa[i]=i; for(int i=1;i<=p;i++) { int x,y; scanf("%d%d",&x,&y); int a=find(x),b=find(y); if(a!=b)fa[a]=b; } for(int i=1;i<=n;i++) { int t=find(i); if(!belong[t]) { v[++cnt]=1; belong[t]=cnt; } else v[belong[t]]++; } f[0]=1; for(int i=1;i<=cnt;i++) for(int j=n;j>=v[i];j--) if(f[j-v[i]])f[j]=1; int minn=M,ans; for(int i=0;i<=n;i++) if(f[i]&&abs(i-m)<minn) { minn=abs(i-m); ans=i; } printf("%d",ans); return 0; }