首页 > 试题广场 >

小红的双生英雄

[编程题]小红的双生英雄
  • 热度指数:2358 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}小红有 n 个英雄,第 i 个英雄的 cost 是 a_i,战斗力为 b_i。另外,存在一些“双生英雄”关系,如果同时上阵某一对英雄,则可以获得额外的战斗力收益。
\hspace{15pt}现在小红最多可以上阵四名英雄,且要求总 cost 不超过C。小红希望你求出组队的最大战斗力。

输入描述:
\hspace{15pt}第一行输入三个整数 n,C,m \left(1 \leqq n,C \leqq 10^3;\ 0 \leqq m \leqq n/2\right) 代表英雄数量、总cost限制、双生英雄的对儿数。 
\hspace{15pt}此后 n 行,第 i 行输入两个正整数 a_i,b_i \left(1 \leqq a_i,b_i \leqq 10^9\right) 代表第 i 个英雄的 cost 和战斗力。
\hspace{15pt}此后 m 行,第 i 行输入三个正整数 u_i,v_i,w_i \left(1 \leqq u_i,v_i \leqq n; u_i \neq v_i; 1 \leqq w_i \leqq 10^9\right) 代表第 u_i 和第 v_i 个英雄是双生英雄,同时上阵可以额外增加 w_i 战斗力。

\hspace{15pt}除此之外,保证每个英雄最多只存在一对双生英雄关系。对于 40\% 的用例,额外保证 m=0


输出描述:
\hspace{15pt}输出一个整数,代表组队的最大战斗力。
示例1

输入

4 10 1
3 9
4 10
6 15
8 20
1 2 15

输出

34

说明

\hspace{15pt}在这个样例中,小红可以选择上阵第一、二个英雄,获得 9+10+15=34 的战斗力。我们可以证明,这是符合要求的最大战斗力。
示例2

输入

4 1 1
3 9
4 10
6 15
8 20
1 2 15

输出

0
预处理:双生英雄捆绑在1个下标 i
之后就是01背包:当前 i 选英雄0/1/2个取max
import java.util.*;

// 双生英雄捆绑在1个下标i, 4种情况取min: 不选、选1个、都选(触发额外加成)
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt(), c = in.nextInt(), m = in.nextInt();
        int[] a = new int[n], b = new int[n + 1];
        for (int i = 0; i < n; i++) {
            a[i] = in.nextInt(); // cost
            b[i] = in.nextInt(); // attack
        }
        Map<Integer, int[]> link = new HashMap<>();
        for (int i = 0; i < m; i++) {
            int u = in.nextInt() - 1, v = in.nextInt() - 1, w = in.nextInt();
            link.put(u, new int[] {v, w});
            link.put(v, new int[] {u, w});
        }

        int[][] heros = new int[n - m][5]; // 整合英雄 {cost1, atk1, cost2, atk2, w}
        boolean[] used = new boolean[n];
        for (int i = 0, k = 0; i < n; i++) {
            if (used[i]) continue;
            if (link.containsKey(i)) {
                int[] arr = link.get(i);
                int u = i, v = arr[0], w = arr[1];
                heros[k] = new int[] {a[u], b[u], a[v], b[v], w}; // 双生英雄
                used[v] = true;
            } else {
                heros[k] = new int[] {a[i], b[i], INF, 0, 0}; // 单个英雄:cost2置INF表示不可达
            }
            k++;
        }

        long[][][] dp = new long[4 + 1][n - m + 1][c + 1]; // long:结果会很大
        for (int k = 1; k <= 4; k++) {
            for (int i = 1; i <= n - m; i++) {
                int[] h = heros[i - 1];
                int a1 = h[0], b1 = h[1], a2 = h[2], b2 = h[3], w = h[4];
                for (int j = 1; j <= c; j++) {
                    long res = dp[k][i - 1][j]; // 不选
                    if (j >= a1) { // 选英雄1
                        res = Math.max(res, dp[k - 1][i - 1][j - a1] + b1);
                    }
                    if (j >= a2) { // 选英雄2
                        res = Math.max(res, dp[k - 1][i - 1][j - a2] + b2);
                    }
                    if (j >= a1 + a2 && k >= 2) { // 都选+额外奖励
                        res = Math.max(res, dp[k - 2][i - 1][j - a1 - a2] + b1 + b2 + w);
                    }
                    dp[k][i][j] = res;
                }
            }
        }
        System.out.println(dp[4][n - m][c]);
    }
    private final static int INF = Integer.MAX_VALUE / 2;
}



发表于 2025-10-10 11:23:38 回复(0)