• DP题 总结 [更新中]


    建设中 ...

     预防针 : 本蒟蒻代码风格清奇(⊙﹏⊙)b

    一.选学霸

    题目描述

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

    分析:

    看到这题第一下想出的就是并查集, 但仔细想想很容易想到背包问题。

    因为所有水平一样的人必须一起选, 所以, 把水平一样的人看成一件物品。再01背包转移。

    注意此时的最大体积应该为2*m(很容易想到)。最后再枚举体积。最后再注意一下差值一样时取最小。

    AC水题;

    //By zZhBr
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    using namespace std;
    
    int n, m, k;
    
    int f[20010];
    
    inline int find(int x)
    {
        return x == f[x] ? f[x] : f[x] = find(f[x]);
    }
    
    int a[20010];
    
    int dp[20010];
    
    int num[20010];
    int vis[20010]; 
    
    int cnt;
    
    int main()
    {
        scanf("%d%d%d", &n, &m, &k);
        
        for(register int i = 1 ; i <= n ; i ++) f[i] = i;
        
        for(register int i = 1 ; i <= k ; i ++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            
            int fx = find(x), fy = find(y);
            f[fx] = fy;
            
        }
        
        for(register int i = 1 ; i <= n ; i ++)
        {
            int fa = find(i);
            num[fa]++;
            if(!vis[fa]) 
            {
                vis[fa] = 1;
                a[++cnt] = fa;
            }
            
        }
        
        for(register int i = 1 ; i <= cnt ; i ++)
        {
            for(register int j = m * 2 ; j >= num[a[i]] ; j --)
            {
                dp[j] = max(dp[j], dp[j-num[a[i]]] + num[a[i]]);
            }
        }
        
        int ans = 0;
        
        for(register int i = 0 ; i <= m * 2 ; i ++)
        {
            if(abs(ans - m) > abs(dp[i] - m)) ans = dp[i];
            else if(abs(ans - m) == abs(dp[i] - m)) ans = min(ans, dp[i]);
        }
        
        printf("%d", ans);
        
        return 0;
    }
    选学霸
  • 相关阅读:
    python活力练习Day13
    检测一个字符串在另外一个字符串中的位置
    Python活力练习Day12
    Python多进程与单进程效率对比
    HTML-Note
    Python判断自定义的参数格式是否正确
    图片的灰与彩
    Git常用命令
    Linux 单引号和双引号的区别
    类函数中获取进程池对象的地址
  • 原文地址:https://www.cnblogs.com/BriMon/p/8933805.html
Copyright © 2020-2023  润新知