codevs 3372 选学霸(hash+并查集+多重背包)

先通过并查集处理出来有多少种不同的集合,每个集合有多少人。一定要不要忘记了与别的没有联系的独立点。

并查集的时候可以通过hash处理出来每个数目相同的集合的个数。

这样以人数为权值,个数为限制进行多重背包,结果就是答案。

题目链接:http://codevs.cn/problem/3372/

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-8
#define M 1000100
#define LL long long
//#define LL long long
#define INF 0x3f3f3f
#define PI 3.1415926535898
#define mod 1000000007

const int maxn = 30010;

using namespace std;

int vis1[maxn];
int vis2[maxn];
int vis[maxn];
int num[maxn];

int dp[2*maxn];
int fa[maxn];

struct node
{
    int snum;
    int sum;
} p[maxn];

int n;
void init()
{
    for(int i = 0; i <= n; i++) fa[i] = i;
    memset(vis1, 0, sizeof(vis1));
    memset(vis2, 0, sizeof(vis2));
    memset(dp, 0, sizeof(dp));
    memset(vis, 0, sizeof(vis));
}

int Find(int x)
{
    if(x != fa[x]) fa[x] = Find(fa[x]);
    return fa[x];
}

void add(int x, int y)
{
    int x1, y1;
    x1 = Find(x);
    y1 = Find(y);
    if(x1 != y1) fa[x1] = y1;
}

int main()
{
    int m, k;
    while(~scanf("%d %d %d",&n, &m, &k))
    {
        init();
        int x, y;
        for(int i = 0; i < k; i++)
        {
            scanf("%d %d",&x, &y);
            vis[x] = 1;
            vis[y] = 1;
            add(x, y);
        }
        int ans = 0;
        int xsum = 0;
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i])
            {
                xsum ++;
                continue;
            }
            int s = Find(i);
            vis1[s] ++;
        }
        for(int i = 1; i <= n; i++)
        {
            if(!vis1[i]) continue;
            num[ans++] = vis1[i];
        }
        sort(num, num+ans);
        for(int i = 0; i < ans; i++) vis2[num[i]]++;
        int cnt = 0;
        for(int i = 1; i <= n; i++)
        {
            if(!vis2[i]) continue;
            p[cnt].snum = i;
            p[cnt++].sum = vis2[i];
        }
        int v = 2*(m+1);
        dp[0] = 1;
        for(int i = 0; i < cnt; i++)
        {
            for(int j = v; j >= 0; j--)
            {
                if(!dp[j]) continue;
                for(int kk = 1; kk <= p[i].sum; kk++)
                {
                    if(kk*p[i].snum+j > v) break;
                    if(dp[kk*p[i].snum+j]) break;
                    dp[kk*p[i].snum+j] = 1;
                }
            }
        }
        int lx, rx;
        for(int i = m; i >= 0; i--)
        {
            if(dp[i])
            {
                lx = i;
                break;
            }
        }
        for(int i = m; i <= 2*(m+1); i++)
        {
            if(dp[i])
            {
                rx = i;
                break;
            }
        }
        lx = max(lx, 0);
        rx = min(rx, 2*(m+1));
        int sx = abs(m-lx);
        int sy = abs(rx-m);
        if(sx <= xsum)
        {
            sx = 0;
            lx = m;
        }
        else
        {
            sx -= xsum;
            lx += xsum;
        }
        if(sy < sx)
        {
            cout<<rx<<endl;
            continue;
        }
        cout<<lx<<endl;
    }
    return 0;
}
/*
10 4 9
8 2
1 5
5 10
9 7
10 3
3 4
4 6
8 9
6 8
0

5 3 3
1 2
2 3
3 4
4

*/
时间: 2024-10-14 00:32:30

codevs 3372 选学霸(hash+并查集+多重背包)的相关文章

[luogu P2170] 选学霸(并查集+dp)

题目传送门:https://www.luogu.org/problem/show?pid=2170 题目描述 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议.所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近 输入输出格式 输入格式: 第一行,三个正整数N,M,K. 第2...K行,每行2个数,表示一对实力相当的人的编号(编号为1-N) 输出格式: 一行,表示既不让同学们抗议,又与原来的M尽可能接

3372 选学霸

3372 选学霸 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Description 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议.所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近. 输入描述 Input Description 第一行,三个正整数N,M,K. 第2...K行,每行2个数,表示一对实力相当的人的编号(编号为1…N). 输

CF741B Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses 并查集 01背包

title CF741B 简化题意: 有 \(n\) 个人 \((1<=n<=1000)\) ,每个人有一个重量 \(w_i(1\leqslant w_i\leqslant 1000)\) 和一个魅力值 \(b_i(1\leqslant b_i\leqslant 10^6)\) . \(n\) 个人之间有 \(m(1\leqslant m\leqslant min(\frac{n(n-1)}{2}, 10^5))\) 个关系.第 \(i\) 个关系由两个数字 \(x_i\) 和 \(y_i\)

POJ 2513(字典树hash+并查集+欧拉通路)

Colored Sticks Time Limit: 5000MS   Memory Limit: 128000K Total Submissions: 31015   Accepted: 8180 Description You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a st

F2 - Spanning Tree with One Fixed Degree - 并查集+DFS

这道题还是非常有意思的,题意很简单,就是给定一个图,和图上的双向边,要求1号节点的度(连接边的条数)等于K,求这棵树的生成树. 我们首先要解决,如何让1号节点的度时为k的呢???而且求的是生成树,意思是不是所有边都会选择.那么我们如何选择才能保证1号节点有K个度呢???这里就要考虑联通分量的问题了,我们刨除1号点,那么联通分量的个数,就是我们让图联通的最小个数,因此我们需要用并查集,把点分在不同的联通块内部. 再考虑我们每个联通块,至少需要1条连接1号点的边.不够K再添加连接1号点的边. 然后考

洛谷1455 搭配购买(并查集)

洛谷1455 搭配购买 本题地址:http://www.luogu.org/problem/show?pid=1455 题目描述 明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有n朵云,云朵已经被老板编号为1,2,3,……,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉

并查集+背包 【CF741B】 Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses

Descirption 有n个人,每个人都有颜值bi与体重wi.剧场的容量为W.有m条关系,xi与yi表示xi和yi是好朋友,在一个小组. 每个小组要么全部参加舞会,要么参加人数不能超过1人. 问保证总重量不超过W,剧场中的颜值最大能到多少? Input 第一行,三个整数n,m,w 第二行,n个整数w1,w2,...,wn 第三行,n个整数b1,b2,...,bn 接下来m行,每行表示一个关系,第i行有两个整数xi和yi. 每一组朋友关系都是不同的. Output ?一行,表示最大的魅力值总和.

CODEVS【3372】选学霸

题目描述 Description 老师想从N名学生中选M人当学霸,但有K对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议.所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的M尽可能接近. 输入描述 Input Description 第一行,三个正整数N,M,K. 第2...K行,每行2个数,表示一对实力相当的人的编号(编号为1…N). 输出描述 Output Description 一行,表示既不让同学们抗议,又与原来的M尽可能接近的选出学霸的数

codevs 1078最小生成树 Kruskal+并查集

题目描述 Description 农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场.当然,他需要你的帮助. 约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场.为了使花费最少,他想铺设最短的光纤去连接所有的农场. 你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案. 每两个农场间的距离不会超过100000 输入描述 Input Description 第一行: 农场的个数,N(3<=N<=100).