• 野餐规划(最小生成树性质)⭐


    题面

    一群小丑演员,以其出色的柔术表演,可以无限量的钻进同一辆汽车中,而闻名世界。

    现在他们想要去公园玩耍,但是他们的经费非常紧缺。

    他们将乘车前往公园,为了减少花费,他们决定选择一种合理的乘车方式,可以使得他们去往公园需要的所有汽车行驶的总公里数最少。

    为此,他们愿意通过很多人挤在同一辆车的方式,来减少汽车行驶的总花销。

    由此,他们可以很多人驾车到某一个兄弟的家里,然后所有人都钻进一辆车里,再继续前进。

    公园的停车场能停放的车的数量有限,而且因为公园有入场费,所以一旦一辆车子进入到公园内,就必须停在那里,不能再去接其他人。

    现在请你想出一种方法,可以使得他们全都到达公园的情况下,所有汽车行驶的总路程最少。

    输入格式

    第一行包含整数n,表示人和人之间或人和公园之间的道路的总数量。

    接下来n行,每行包含两个字符串A、B和一个整数L,用以描述人A和人B之前存在道路,路长为L,或者描述某人和公园之间存在道路,路长为L。

    道路都是双向的,并且人数不超过20,表示人的名字的字符串长度不超过10,公园用“Park”表示。

    再接下来一行,包含整数s,表示公园的最大停车数量。

    你可以假设每个人的家都有一条通往公园的道路。

    输出格式

    输出“Total miles driven: xxx”,其中xxx表示所有汽车行驶的总路程。

    输入样例:

    10
    Alphonzo Bernardo 32
    Alphonzo Park 57
    Alphonzo Eduardo 43
    Bernardo Park 19
    Bernardo Clemenzi 82
    Clemenzi Park 65
    Clemenzi Herb 90
    Clemenzi Eduardo 109
    Park Herb 24
    Herb Eduardo 79
    3
    

    输出样例:

    Total miles driven: 183
    

    题解

    最小生成树的子树还是最小生成树

    先把题目中的s限制去掉, 就是求G = (V, E)的最小生成树

    所以我们就是把G的最小生成树链接根(Park)的一些边去掉, 断出来一些子最小生成树

    然后通过一些和这些子最小生成树相连的边(另一端必须连在Park上), 将断出来的子树重新练回Park

    求得就是最小花费

    思路清楚了, 就好写了

    d[i][0] 表示第i棵子树链接Park的最小权值

    d[i][j](j != 0) 表示第i棵子树和第j棵链接的边的最小权值

    最多有20棵子树, 直接状压选择哪些子树还连在Park, 然后再选择断出来的子树连回去的最小边相加

    最后取最小值就行了

    #include <bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    #define per(i,a,b) for(int i=a;i>=b;--i)
    #define fi first
    #define se second
    using namespace std;
    typedef pair<int, int> PII;
    typedef long long ll;
    
    const int maxn = 22;
    
    struct rec { int x, y, z; } e[2000];
    
    bool operator<(rec& a, rec& b) { return a.z < b.z; }
    
    int n, s, fa[maxn], ans, v[maxn], res;
    int b[maxn], cnt, d[maxn][maxn];
    unordered_map<string, int> mp;
    
    int get(int x) { return x == fa[x] ? x : fa[x] = get(fa[x]); }
    
    void dfs(int cur, int k, int m, int p)
    {
        if (cur >= res || (cnt - p + 1) < k) return;
        if (m == cnt) { res = cur; return; }
    
        if (k)
        {
            rep(i, p, cnt)
                if (!v[i])
                {
                    v[i] = 1;
                    dfs(cur + d[i][0], k - 1, m + 1, i + 1);
                    v[i] = 0;
                }
        }
        else
            rep(i, 1, cnt)
            if (!v[i])
            {
                v[i] = 1;
                int mi = 2e9;
                rep(j, 1, cnt) if (v[j]) mi = min(mi, d[i][j]);
                dfs(cur + mi, 0, m + 1, 0);
                v[i] = 0;
            }
    }
    
    int main()
    {
        ios::sync_with_stdio(0); cin.tie(0);
        cin >> n; mp["Park"] = 0;
    
        rep(i, 1, n)
        {
            string a, b; int c;
            cin >> a >> b >> c;
            if (!mp.count(a)) mp[a] = mp.size();
            if (!mp.count(b)) mp[b] = mp.size();
            e[i] = { mp[a], mp[b], c };;
        } cin >> s;
    
        rep(i, 1, 21) fa[i] = i;
        memset(d, 0x3f, sizeof d);
        sort(e + 1, e + n + 1);
    
        rep(i, 1, n)
        {
            int x = get(e[i].x), y = get(e[i].y);
            if (y == 0) y = x, x = 0;
            if (x == y || (x == 0 && b[y])) continue;
            if (x == 0) { d[++cnt][0] = e[i].z; b[y] = cnt; res += e[i].z; }
            else if (b[x] && b[y])
            {
                d[b[y]][b[x]] = min(d[b[y]][b[x]], e[i].z);
                d[b[x]][b[y]] = d[b[y]][b[x]];
            }
            else if (b[x]) fa[y] = x, ans += e[i].z;
            else if (b[y]) fa[x] = y, ans += e[i].z;
            else fa[y] = x, ans += e[i].z;
        }
    
        if (cnt > s) { res = 1e9; dfs(0, s, 0, 1); }
        cout << "Total miles driven: " << ans + res;
        return 0;
    }
    
  • 相关阅读:
    webpack安装、环境搭建和基本配置
    webpack知识点总结
    Vue之Vuex的使用
    vue之获取滚动条位置
    MongoDB ORM mongoose 配置和使用
    sequelize之通过options生成sql语句
    七牛上传之PutExtra的使用
    使用ssl-validator识别证书信息
    深入理解计算机系统(第三版)第八章重要内容摘要
    深入理解计算机系统(第三版)第七章重要内容摘要
  • 原文地址:https://www.cnblogs.com/2aptx4869/p/12900955.html
Copyright © 2020-2023  润新知