• CODEVS【3372】选学霸


    题目描述 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

    实力相当的人要尽量选上,因此我们可以利用并查集把实力相当的人合并,每个集中的老大都有自己的盟友(实力相当的人)(第i个人盟友个数用w[i]表示,初始化w[i]=1),当合并两个集时(f[a]=b),要注意把a的盟友同时合并给b,即w[b]+=w[a],a的盟友自然成了b的盟友,a现在只是一个小喽罗,所以w[a]=0;现在开始枚举w[i]不为0的人,则可以把一个个集看作一个个团队(也可以是单人团队),w[i]表示团队人的个数,++k,最终k表示团队的个数。问题转化为了01背包问题。但是注意此问题要求的是差的绝对值最小的值,所以可以从0开始向两边枚举(枚举dp[m-i]是否等于m-i,dp[m+i]是否等于m+i),第一个枚举到的值输出即可。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<vector>
     6 #include<algorithm>
     7 #include<cstring>
     8 #include<vector>
     9 #include<map>
    10 #include<stack>
    11 #define maxn 30000+50
    12 #define inf 0x7fffffff
    13 #define  xiao 1e-9
    14 using namespace std;
    15 int f[maxn],w[maxn],a[maxn],dp[2*maxn];
    16 int find(int x)
    17 {
    18     if(f[x]==x) return x;
    19     else return find(f[x]);
    20 }
    21 int main()
    22 {
    23     int n,m,k,b,x;
    24     cin>>n>>m>>k;
    25     for(int i=1;i<=n;++i){f[i]=i;w[i]=1;}
    26     for(int i=1;i<=k;++i) 
    27       {
    28           scanf("%d%d",&x,&b);
    29           int fa=find(x),fb=find(b);
    30           if(fa!=fb)
    31             {
    32                  f[x]=b;
    33                  w[b]+=w[x];
    34                  w[x]=0;
    35             }
    36       }
    37       k=0;
    38     for(int i=1;i<=n;++i)
    39       {
    40           if(w[i]!=0) a[++k]=w[i];
    41       }
    42     for(int i=1;i<=k;++i)
    43       {
    44           for(int j=2*m+1;j>=a[i];--j)
    45               {
    46                   dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
    47           }
    48       }
    49       for(int i=0;i<=m;++i)
    50       {
    51            if(dp[m-i]==m-i){cout<<m-i;break;}
    52            if(dp[m+i]==m+i) {cout<<m+i;break;}
    53 }
    54   return 0;
    55 }
    56           
    View Code选学霸
  • 相关阅读:
    JavaEE高级-JPA学习笔记
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
    jQueryrocket
  • 原文地址:https://www.cnblogs.com/TYH-TYH/p/4918276.html
Copyright © 2020-2023  润新知