【题目描述】
老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议。所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近。
【输入描述】
第一行,三个正整数N、M、K;
第2~K行,每行2个数,表示一对实力相当的人的编号(编号为1~N)。
【输出描述】
一行,表示既不让同学们抗议,又与原来的M尽可能接近的选出学霸的数目(如果有两种方案与M的差的绝对值相等,选较小的一种)。
【样例输入】
4 3 2
1 2
3 4
【样例输出】
2
【数据范围及提示】
100%的数据,N,P <= 30000。
源代码: #include<cstdio> #include<algorithm> using namespace std; int m,n,k,Num(0),F[30001]={0}; int V[30001],Belong[30001]; bool f[30001]; int Find(int t) { if (!F[t]) return t; return F[t]=Find(F[t]); } int main() { scanf("%d%d%d",&n,&m,&k); for (int a=1;a<=k;a++) { int t1,t2; scanf("%d%d",&t1,&t2); int T1=Find(t1); int T2=Find(t2); if (T1!=T2) F[T1]=T2; } for (int a=1;a<=n;a++) //并查集预处理。 { int t=Find(a); if (!Belong[t]) { V[++Num]=1; Belong[t]=Num; } else V[Belong[t]]++; } f[0]=true; for (int a=1;a<=Num;a++) //情况若能到达,便进行标记。 for (int b=n;b>=V[a];b--) if (f[b-V[a]]) f[b]=true; int Min=30000,ans; for (int a=0;a<=n;a++) //对于能够到达的情况便进行处理。 if (f[a]&&abs(a-m)<Min) { Min=abs(a-m); ans=a; } printf("%d",ans); return 0; }