• b_lg_选学霸(并查集+01背包)


    老师想从 n 名学生中选 m 人当学霸,但有 k 对人实力相当,如果实力相当的人中,一部分被选上,另一部分没有,同学们就会抗议。
    所以老师想请你帮他求出他该选多少学霸,才能既不让同学们抗议,又与原来的 m 尽可能接近。

    思路
    注意:是与m的差的绝对值最小化,所以选的人数可>m,也可≤m

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=2e4+5;
    int n,m,k, fa[N], sz[N], f[N], s[N];
    int find(int u) {
        return fa[u]==u ? u : fa[u]=find(fa[u]);
    }
    void merge(int u, int v) {
        int fu=find(u), fv=find(v);
        if (fu!=fv) {
            fa[fu]=fv;
            sz[fv]+=sz[fu];
        }
    }
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        cin>>n>>m>>k;
        for (int i=1; i<=n; i++) fa[i]=i, sz[i]=1;
        for (int i=0; i<k; i++) {
            int u,v; cin>>u>>v;
            merge(u,v);
        }
        int tot=0, cap=min(n,2*m);
        for (int i=1; i<=n; i++) if (fa[i]==i)
            s[tot++]=sz[i];  //每个连通块的人数
        //对于每个连通块都可以选或不选
        for (int i=0; i<tot; i++)
        for (int j=cap; j>=s[i]; j--) {
            f[j]=max(f[j], f[j-s[i]]+s[i]);
        }
        ll ans=-1, mi=INT_MAX;
        for (int j=0; j<=cap; j++) {
            int d=abs(f[j]-m);
            if (d<mi || (d==mi && f[j]<ans)) {
                mi=d, ans=f[j];
            }
        }
        cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    javaweb学习2
    javaweb学习1
    Java学习17
    python 正则表达式
    python 常用库
    python 常用内置函数
    python 函数高级功能
    python 正则表达式findall
    tcpdump
    安卓软件学习进度_1
  • 原文地址:https://www.cnblogs.com/wdt1/p/13807241.html
Copyright © 2020-2023  润新知