1 条题解

  • 0
    @ 2025-8-24 23:16:40

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 沉石鱼惊旋
    已完成今日我对着铁质的凳子踢了五下然后把那堆钢栏杆在地上滚了一下然后把椅子夹在了篮筐上大学习

    搬运于2025-08-24 23:16:40,当前版本为作者最后更新于2025-05-24 18:09:06,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    做题需要先看数据范围。发现 n8n\leq 8,显然我们可以枚举全排列枚举删除顺序。使用打删除标记遍历每一条边来模拟题意。

    枚举全排列可以使用 next_permutation 或 DFS 搜索(如 std)。

    mmn2n^2 级别的,故复杂度 O(n!n2)\mathcal O(n! n^2)

    当然本题也可以通过状态压缩 DP 做到 O(2nn2)\mathcal O(2^n n^2) 的复杂度。

    n=8n=8 是因为放在这个位置被钦定使用枚举全排列通过,作者写了一份 Python 代码发现 n=9n=9 就跑的很慢了。

    另外 C++ 注意要开 long long,其他语言同理。


    第一档部分分每次选度数最小的出来做。第二档其实也是,但是因为树的特殊性质边权之和就是答案。

    刻意卡了一下每次选度数最小或者是代价最小的拉出来跑贪心或者凭这个性质做搜索的剪枝。分别被卡到了 7070 分和 6060 分。


    关于题目名称,和本场比赛彩蛋有关。


    这是我写的 std。

    // std
    #include <bits/stdc++.h>
    using namespace std;
    template <typename T>
    void chkmn(T &x, T y) { x = min(x, y); }
    typedef long long ll;
    int n, m;
    vector<array<int, 2>> a[30];
    bool vis[30];
    bool del[30];
    int v[30];
    ll ans = 1e18;
    void dfs(int dep)
    {
        if (dep == n + 1)
        {
            memset(del, 0, sizeof(del));
            ll tmp = 0;
            for (int i = 1; i <= n; i++)
            {
                int u = v[i];
                int tot = 0;
                ll sum = 0;
                for (auto [v, w] : a[u])
                {
                    if (del[v])
                        continue;
                    tot++;
                    sum += w;
                }
                del[u] = 1;
                tmp += sum * tot;
            }
            chkmn(ans, tmp);
            return;
        }
        for (int i = 1; i <= n; i++)
        {
            if (vis[i])
                continue;
            v[dep] = i;
            vis[i] = 1;
            dfs(dep + 1);
            vis[i] = 0;
            v[dep] = 0;
        }
    }
    int main()
    {
        cin >> n >> m;
        while (m--)
        {
            int u, v, w;
            cin >> u >> v >> w;
            a[u].push_back({v, w});
            a[v].push_back({u, w});
        }
        dfs(1);
        cout << ans << '\n';
        return 0;
    }
    

    用 GPT 4o 写了个代码结果常数太大过不去,比我写的这份慢了十倍。

    # Python std
    n, m = map(int, input().split())
    e = [[]]
    for i in range(n + 1):
        t = []
        for j in range(n + 1):
            t.append(-1)
        e.append(t)
    for i in range(m):
        u, v, w = map(int, input().split())
        e[u][v] = e[v][u] = w
    vis = [0] * (n + 1)
    vv = [-1] * (n + 1)
    
    ans = 10**18
    
    
    def dfs(dep):
        global ans
        if dep == n + 1:
            dele = [0] * (n + 1)
            tmp = 0
            for i in range(1, n + 1):
                u = vv[i]
                tot = 0
                sum = 0
                for v in range(1, n + 1):
                    if e[u][v] == -1:
                        continue
                    if dele[v]:
                        continue
                    tot += 1
                    sum += e[u][v]
                dele[u] = 1
                tmp += sum * tot
            ans = min(ans, tmp)
            return
        for u in range(1, n + 1):
            if vis[u]:
                continue
            vis[u] = 1
            vv[dep] = u
            dfs(dep + 1)
            vis[u] = 0
            vv[dep] = -1
    
    
    dfs(1)
    print(ans)
    

    这份是 GPT 4o 写的 Java 代码。

    // GPT 4o Java
    
    import java.util.*;
    
    public class Main {
        static int n, m;
        static List<int[]>[] graph;
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
    
            n = sc.nextInt();
            m = sc.nextInt();
    
            graph = new ArrayList[n + 1];
            for (int i = 1; i <= n; ++i) {
                graph[i] = new ArrayList<>();
            }
    
            for (int i = 0; i < m; ++i) {
                int u = sc.nextInt(), v = sc.nextInt(), w = sc.nextInt();
                graph[u].add(new int[]{v, w});
                graph[v].add(new int[]{u, w});
            }
    
            int[] order = new int[n];
            for (int i = 0; i < n; ++i) order[i] = i + 1;
    
            long ans = Long.MAX_VALUE;
    
            do {
                // 深复制图结构
                List<int[]>[] g = new ArrayList[n + 1];
                for (int i = 1; i <= n; ++i) {
                    g[i] = new ArrayList<>();
                    for (int[] edge : graph[i]) {
                        g[i].add(new int[]{edge[0], edge[1]});
                    }
                }
    
                boolean[] deleted = new boolean[n + 1];
                long cost = 0;
    
                for (int idx = 0; idx < n; ++idx) {
                    int u = order[idx];
                    int deg = 0;
                    long sum = 0;
    
                    for (int[] edge : g[u]) {
                        int v = edge[0], w = edge[1];
                        if (!deleted[v]) {
                            deg++;
                            sum += w;
                        }
                    }
    
                    cost += (long) deg * sum;
                    deleted[u] = true;
    
                    for (int[] edge : g[u]) {
                        int v = edge[0];
                        g[v].removeIf(e -> e[0] == u);
                    }
    
                    g[u].clear();
                }
    
                ans = Math.min(ans, cost);
    
            } while (nextPermutation(order));
    
            System.out.println(ans);
        }
    
        // Java 没有内建的 next_permutation,需要手写
        static boolean nextPermutation(int[] arr) {
            int i = arr.length - 2;
            while (i >= 0 && arr[i] >= arr[i + 1]) i--;
            if (i < 0) return false;
    
            int j = arr.length - 1;
            while (arr[j] <= arr[i]) j--;
            swap(arr, i, j);
            reverse(arr, i + 1, arr.length - 1);
            return true;
        }
    
        static void swap(int[] arr, int i, int j) {
            int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp;
        }
    
        static void reverse(int[] arr, int l, int r) {
            while (l < r) swap(arr, l++, r--);
        }
    }
    
    • 1

    信息

    ID
    12304
    时间
    1000ms
    内存
    512MiB
    难度
    2
    标签
    (无)
    递交数
    0
    已通过
    0
    上传者