zoukankan      html  css  js  c++  java
  • 洛谷P2170 选学(da)霸(lao)

    题目:https://www.luogu.org/problemnew/show/P2170

    题目描述

    老师想从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

    解析

    唉,我并查集都忘得差不多了orz。

    如果一些人的实力相同,那么他们中要么全选,要么不选。

    这像不像01背包呢?

    用并查集处理水平相同的人,如果相同归在一块,看成一个整体。

    这个整体的 价值 和 所占用的体积 都为这个整体的人数。

    然后就是一个背包dp啦,可以用f[i]表示体积为i能放多少人,如果f[i]==i则代表这种方案合法。

    当然也可以采用可行性dp(本文即是),f[i]表示i人能否被取到。

    没有得满分的dalao们注意啦:

    ①你有可能一个人都不选

    ②不要码错并查集(估计只有我这么。。。。。。)

    ③计算每一个整体的时候,判断某个属于哪个集体时用find(x)而不是fa[x](见代码)

    ④没了,祝您ak愉快

    代码如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<cstdlib> 
     7 using namespace std;
     8 #define maxn 200100
     9 int n,m,k,ra,rb;
    10 int fa[maxn];
    11 bool f[2*maxn];
    12 int groupr[maxn];
    13 int group[maxn],tot;
    14 int finda(int x){
    15     if (fa[x]==x) return fa[x];
    16     else return fa[x]=finda(fa[x]);
    17 }
    18 void unionn(int x,int y){
    19     int fx=finda(x),fy=finda(y);
    20     if (fx==fy) return;
    21     fa[fx]=fy;
    22 }
    23 int main(){
    24     scanf("%d%d%d",&n,&m,&k);
    25     for (int i=1;i<=n;++i) fa[i]=i;
    26     for (int i=1;i<=k;++i){
    27         scanf("%d%d",&ra,&rb);
    28         //if (ra>rb) swap(ra,rb); 
    29         unionn(ra,rb);
    30     }
    31     for (int i=1;i<=n;++i){
    32         groupr[finda(i)]++; //不要写成fa[i]
    33     }
    34     for (int i=1;i<=n;++i){
    35         if (groupr[i]){
    36             group[++tot]=groupr[i];
    37         }
    38     }
    39     f[0]=true;
    40     for (int i=1;i<=tot;++i){
    41         for (int j=2*m;j>=group[i];--j){
    42             if (f[j-group[i]]){
    43                 f[j]=true;
    44             }
    45         }
    46     }
    47     for (int i=0;i<=m;++i){
    48         if (f[m-i]){
    49             printf("%d",m-i);
    50             return 0;
    51         }
    52         if (f[m+i]){
    53             printf("%d",m+i);
    54             return 0;
    55         }
    56     } 
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    [LeetCode]Binary Tree Level Order Traversal
    [LeetCode]Binary Tree Postorder Traversal
    Netty(六):NioServerSocketChannel源码解析
    Netty(五):ServerBootstrap启动流程
    Netty(四):AbstractChannel源码解析
    Netty(三):IdleStateHandler源码解析
    自定义fastjson对枚举类型的序列化及反序列化过程
    TCP连接过程及报文解析
    Netty(二):数据在ChannelPipeline中的流经
    Netty(一):ByteBuf读写过程图解
  • 原文地址:https://www.cnblogs.com/gjc1124646822/p/7795483.html
Copyright © 2011-2022 走看看