选学霸

题目描述
老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议。所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近
输入输出格式
输入格式:
第一行,三个正整数N,M,K。
第2...K行,每行2个数,表示一对实力相当的人的编号(编号为1…N)
输出格式:
一行,表示既不让同学们抗议,又与原来的M尽可能接近的选出学霸的数目。(如果有两种方案与M的差的绝对值相等,选较小的一种:)
输入输出样例
输入样例#14 3 2
1 2
3 4
输出样例#12
说明
100%的数据N,P<=20000
题面

 解:

根据题意可得,对于实力相当的一群人,要么不选,要么都选
我们就把这一群人看成一个物品,
跑一边背包,体积范围为 0->m*2
然后枚举所有体积,找到最合适的答案

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 const int N=2e4+20;
 5 int n,f[N],size[N];
 6 int F(int x)
 7 {
 8     if(x==f[x]) return x;
 9     else return f[x]=F(f[x]);
10 }
11 int m,k,a[N],v[N];
12 int main()
13 {
14     scanf("%d%d%d",&n,&m,&k);
15     for(int i=1;i<=n;++i) f[i]=i;
16     for(int i=1,x,y;i<=k;++i)
17     {
18         scanf("%d%d",&x,&y);
19         x=F(x);y=F(y);
20         f[x]=f[y]=min(x,y);
21     }
22     for(int i=1,fa;i<=n;++i)
23     {
24         fa=F(i);size[fa]++;
25         if(!v[fa]) v[fa]=1,a[++a[0]]=fa;
26     }
27     memset(f,0,sizeof(f));
28     for(int i=1;i<=a[0];++i)
29      for(int j=m*2;j>=size[a[i]];--j)
30       f[j]=max(f[j],f[j-size[a[i]]]+size[a[i]]);
31     v[0]=0;
32     for(int j=0;j<=m*2;++j)
33      if(abs(v[0]-m)>abs(f[j]-m)) v[0]=f[j];
34      else if(abs(v[0]-m)==abs(f[j]-m)) v[0]=min(v[0],f[j]);
35     cout<<v[0];
36     return 0;
37 }
代码

 

posted @ 2018-04-02 19:04  月亮茶  阅读(304)  评论(0编辑  收藏  举报