选学霸

【题目描述】

老师想从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;
}
posted @ 2016-08-17 15:20  前前前世。  阅读(155)  评论(0编辑  收藏  举报