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