首页 > 试题广场 >

小红的双生英雄

[编程题]小红的双生英雄
  • 热度指数:2347 时间限制: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)
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define MAX(x,y) ((x) > (y)) ? (x) : (y)

typedef struct actor_info {
    int cost;
    int power;
    int is_pair;
} ActorInfo;

typedef struct pair_actor {
    int x;
    int y;
    int x_power;
    int y_power;
    int x_cost;
    int y_cost;
    int pair_cost;
    uint64_t pair_power;
} PairActor;

int main() {
    int actor_cnt = 0;
    int max_cost = 0;
    int pair_cnt = 0;
    scanf("%d %d %d", &actor_cnt, &max_cost, &pair_cnt);

    ActorInfo info[actor_cnt + 1];
    memset(info, 0, sizeof(info));
    for (int i = 1; i <= actor_cnt; i++) {
        scanf("%d %d", &info[i].cost, &info[i].power);
    }

    PairActor pair[pair_cnt];
    memset(pair, 0, sizeof(pair));
    for (int i = 0; i < pair_cnt; i++) {
        scanf("%d %d %ld", &pair[i].x, &pair[i].y, &pair[i].pair_power);

        info[pair[i].x].is_pair = 1;
        info[pair[i].y].is_pair = 1;

        pair[i].x_power = info[pair[i].x].power;
        pair[i].y_power = info[pair[i].y].power;
        pair[i].x_cost = info[pair[i].x].cost;
        pair[i].y_cost = info[pair[i].y].cost;
        pair[i].pair_cost = pair[i].x_cost + pair[i].y_cost;
        pair[i].pair_power += info[pair[i].x].power + info[pair[i].y].power;
    }


    uint64_t dp[5][1001] = {0};
    for (int i = 1; i <= actor_cnt; i++) {
        // 跳过双生英雄
        if (info[i].is_pair) {
            continue;
        }
        for (int j = 4; j > 0; j--) {
            for (int k = max_cost; k >= info[i].cost; k--) {
                // 两种情况最大值
                // 不选i英雄:dp[j][k]
                // 选i英雄:dp[j - 1][k - info[i].cost] + info[i].power
                dp[j][k] = MAX(dp[j][k], dp[j - 1][k - info[i].cost] + info[i].power);
            }
        }
    }


    for (int i = 0; i < pair_cnt; i++) {
        for (int j = 4; j > 0; j--) {
            for (int k = max_cost; k > 0; k--) {
                // 4种情况最大值
                // 不选:dp[j][k]
                // 选 x y:dp[j - 2][k - pair[i].pair_cost] + pair[i].pair_power
                // 选x:dp[j - 1][k - pair[i].x_cost] + pair[i].x_power
                // 选y:dp[j - 1][k - pair[i].y_cost] + pair[i].y_power
                uint64_t best_building = dp[j][k];
                if (k > pair[i].pair_cost && j >= 2) {
                    best_building = MAX(best_building, dp[j - 2][k - pair[i].pair_cost] + pair[i].pair_power);
                }
                if (k > pair[i].x_cost) {
                    best_building = MAX(best_building, dp[j - 1][k - pair[i].x_cost] + pair[i].x_power);
                }
                if (k > pair[i].y_cost) {
                    best_building = MAX(best_building, dp[j - 1][k - pair[i].y_cost] + pair[i].y_power);
                }
                dp[j][k] = best_building;
            }
        }

    }

    uint64_t max_power = 0;
    for (int i = 1; i <= 4; i++) {
        max_power = max_power > dp[i][max_cost] ? max_power : dp[i][max_cost];
    }
    printf("%ld\n", max_power);
}

发表于 2025-10-08 16:14:07 回复(0)
这道题的答案是不是有问题?怎么算都过不了。
发表于 2025-10-08 18:54:38 回复(0)

算法逻辑说明

  • 使用 动态规划dp[i][k][j] 表示前 i 个英雄中选了 k 个,总 cost 为 j 时的最大战斗力。
  • 使用滚动数组优化空间(只保留两层)。
  • 每个英雄最多属于一个“双生对”,处理时避免重复。
  • 对于双生英雄 (u, v),只有当两者都被选时,才加上额外战斗力 w
  • 遍历每个英雄,分情况更新 DP:
  • 只选当前英雄
  • 只选其配对英雄(如果前面已处理)
  • 同时选当前和配对英雄(触发双生加成)

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

type Hero struct {
	cost, v, tp, fnv int64
}

func main() {
	reader := bufio.NewReader(os.Stdin)

	// 读取第一行 n, C, m
	line, _ := reader.ReadString('\n')
	parts := strings.Fields(line)
	n, _ := strconv.Atoi(parts[0])
	costLimit, _ := strconv.Atoi(parts[1])
	m, _ := strconv.Atoi(parts[2])

	// 初始化英雄数组
	heroes := make([]Hero, n+1) // 1-indexed

	// 读取 n 个英雄的 cost 和战斗力
	for i := 1; i <= n; i++ {
		line, _ = reader.ReadString('\n')
		parts = strings.Fields(line)
		a, _ := strconv.ParseInt(parts[0], 10, 64)
		b, _ := strconv.ParseInt(parts[1], 10, 64)
		heroes[i] = Hero{cost: a, v: b}
	}

	// 读取 m 对双生英雄
	for i := 0; i < m; i++ {
		line, _ = reader.ReadString('\n')
		parts = strings.Fields(line)
		u, _ := strconv.Atoi(parts[0])
		v, _ := strconv.Atoi(parts[1])
		w, _ := strconv.ParseInt(parts[2], 10, 64)

		heroes[u].tp = int64(v)
		heroes[v].tp = int64(u)
		heroes[u].fnv = w
		heroes[v].fnv = w
	}

	// DP 数组:dp[滚动][k个英雄][总cost] -> 最大战斗力
	// dp[i&1][k][j] 滚动使用
	const MAX_K = 5
	const MAX_COST = 1001
	var dp [2][MAX_K][MAX_COST]int64

	// 初始化 dp 为 0(Go 默认为 0,安全)
	// 使用滚动数组:cur 和 prev
	for i := 1; i <= n; i++ {
		cur := i & 1
		prev := cur ^ 1

		// 拷贝上一行状态
		for k := 0; k < MAX_K; k++ {
			for j := 0; j <= costLimit; j++ {
				dp[cur][k][j] = dp[prev][k][j]
			}
		}

		tp := heroes[i].tp
		if tp != 0 && int64(tp) < int64(i) {
			// 避免重复处理双生对,只在较大的索引处理
			continue
		}

		// 情况1:只选当前英雄 i
		for k := 1; k < MAX_K; k++ {
			for j := int(heroes[i].cost); j <= costLimit; j++ {
				prevVal := dp[prev][k-1][j-int(heroes[i].cost)]
				if prevVal+heroes[i].v > dp[cur][k][j] {
					dp[cur][k][j] = prevVal + heroes[i].v
				}
			}
		}

		// 如果没有配对英雄,跳过后续双生逻辑
		if tp == 0 {
			continue
		}

		// 情况2:只选配对英雄 tp
		for k := 1; k < MAX_K; k++ {
			tpCost := int(heroes[tp].cost)
			if tpCost > costLimit {
				continue
			}
			for j := tpCost; j <= costLimit; j++ {
				prevVal := dp[prev][k-1][j-tpCost]
				if prevVal+heroes[tp].v > dp[cur][k][j] {
					dp[cur][k][j] = prevVal + heroes[tp].v
				}
			}
		}

		// 情况3:同时选 i 和 tp,触发双生加成
		totalCost := int(heroes[i].cost + heroes[tp].cost)
		if totalCost <= costLimit {
			for k := 2; k < MAX_K; k++ {
				for j := totalCost; j <= costLimit; j++ {
					prevVal := dp[prev][k-2][j-totalCost]
					totalV := prevVal + heroes[i].v + heroes[tp].v + heroes[i].fnv
					if totalV > dp[cur][k][j] {
						dp[cur][k][j] = totalV
					}
				}
			}
		}
	}

	// 在所有选 0~4 个英雄、总 cost <= costLimit 的状态中找最大值
	ans := int64(0)
	final := n & 1
	for k := 0; k < MAX_K; k++ {
		if dp[final][k][costLimit] > ans {
			ans = dp[final][k][costLimit]
		}
	}

	fmt.Println(ans)
}


发表于 2025-09-03 16:27:39 回复(0)

好几个代码应该是有问题的

都是直接单人dp一遍  双人dp一遍  

没有考虑到使用双生时 其中的英雄已经使用过的情况

下面的样例 输出应该为 30 
2 40 1
5 10
5 10
1 2 10
应当将双生的两个英雄作为一个整体考虑
直接四种情况一起转移
#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define C getchar()-48
inline ll read(){
    ll s=0,r=1;
    char c=C;
    for(;c<0||c>9;c=C) if(c==-3) r=-1;
    for(;c>=0&&c<=9;c=C) s=(s<<3)+(s<<1)+c;
    return s*r;
}
#define rep(i,sti,edi) for(int i=sti;i<=edi;i++)
const int N=1e3+10;
int n,cost,m;
ll dp[3][6][N];
struct xin{
    ll cost=0,v=0,tp=0,fnv=0;
}a[N];
int main(){
    n=read(),cost=read(),m=read();
    rep(i,1,n) a[i].cost=read(),a[i].v=read();
    rep(i,1,m){
        int x=read(),y=read();ll v=read();
        a[x].tp=y;a[y].tp=x;
        a[x].fnv=a[y].fnv=v;
    }
    rep(i,1,n){
        int dqkd=i&1;int qmkd=dqkd^1;
        int tpi=a[i].tp;
        rep(k,0,4) rep(j,0,cost) 
            dp[dqkd][k][j]=dp[qmkd][k][j];
        if(tpi&&tpi<i) continue;
        rep(k,1,4) rep(j,a[i].cost,cost) 
            dp[dqkd][k][j]=max(dp[dqkd][k][j],dp[qmkd][k-1][j-a[i].cost]+a[i].v);
        if(!tpi) continue;
        rep(k,1,4) rep(j,a[tpi].cost,cost) 
            dp[dqkd][k][j]=max(dp[dqkd][k][j],dp[qmkd][k-1][j-a[tpi].cost]+a[tpi].v);
        rep(k,2,4) rep(j,a[i].cost+a[tpi].cost,cost) 
            dp[dqkd][k][j]=max(dp[dqkd][k][j],dp[qmkd][k-2][j-a[i].cost-a[tpi].cost]+a[i].v+a[tpi].v+a[i].fnv);      
    }
    ll ans=0;
    rep(k,0,4) ans=max(ans,dp[n&1][k][cost]); 
    cout<<ans;
    return 0;
}


发表于 2025-08-27 20:15:58 回复(0)
from itertools import combinations

n, C, m = map(int, input().split())
heroes = []
for _ in range(n):
    a, b = map(int, input().split())
    heroes.append((a, b))

pair_bonus = {}
for _ in range(m):
    u, v, w = map(int, input().split())
    u -= 1
    v -= 1
    pair_bonus[(u, v)] = w
    pair_bonus[(v, u)] = w

max_power = 0

def calculate_power(team):
    total = 0
    for hero in team:
        total += heroes[hero][1]
    for i in range(len(team)):
        for j in range(i + 1, len(team)):
            u, v = team[i], team[j]
            if (u, v) in pair_bonus:
                total += pair_bonus[(u, v)]
    return total

for i in range(n):
    cost = heroes[i][0]
    if cost <= C:
        power = calculate_power([i])
        if power > max_power:
            max_power = power

for i in range(n):
    for j in range(i + 1, n):
        cost = heroes[i][0] + heroes[j][0]
        if cost <= C:
            power = calculate_power([i, j])
            if power > max_power:
                max_power = power

for i in range(n):
    for j in range(i + 1, n):
        for k in range(j + 1, n):
            cost = heroes[i][0] + heroes[j][0] + heroes[k][0]
            if cost <= C:
                power = calculate_power([i, j, k])
                if power > max_power:
                    max_power = power

for i in range(n):
    for j in range(i + 1, n):
        for k in range(j + 1, n):
            for l in range(k + 1, n):
                cost = heroes[i][0] + heroes[j][0] + heroes[k][0] + heroes[l][0]
                if cost <= C:
                    power = calculate_power([i, j, k, l])
                    if power > max_power:
                        max_power = power

print(max_power)
发表于 2025-04-20 12:46:50 回复(0)

仿 HJ16 购物单 题写的解法,自测通过,但是提交不通过,求大佬帮忙看看。

n,Cost,m = map(int,input().split())

hero_data = {}

con_data = {}

for i in range(1,n+1):

    hero_data[i] = list(map(int,input().split()))

for i in range(1,m+1):

    u,v,w = list(map(int,input().split()))

    u,v = [u,v] if u > v else [v,u]

    con_data[u] = [v,w]

C,V = {},{}

for i in hero_data:

    if i not in con_data:

        C[i] = [0,0]

        V[i] = [0,0,0]

for i in hero_data:

    if i in con_data:

        C[con_data[i][0]][1] = hero_data[i][0]

        V[con_data[i][0]][1] = hero_data[i][1]

        V[con_data[i][0]][2] = con_data[i][1]

    else:

        C[i][0] = hero_data[i][0]

        V[i][0] = hero_data[i][1]

C,V = [C[key] for key in C],[V[key] for key in V]

dp = [[[0]*(Cost+1) for _ in range(len(C)+1)] for _ in range(5)]

for k in range(1,5):

    for i in range(1,len(C)+1):

        for j in range(1,Cost+1):

            dp[k][i][j] = dp[k][i-1][j]    # 不选i英雄

            if C[i-1][0] # 选i英雄

                dp[k][i][j] = max(dp[k][i][j],V[i-1][0]+dp[k-1][i-1][j-C[i-1][0]])

            if C[i-1][1] != 0 and C[i-1][1] # 选羁绊英雄

                dp[k][i][j] = max(dp[k][i][j],V[i-1][1]+dp[k-1][i-1][j-C[i-1][1]])

            if C[i-1][1] != 0 and C[i-1][0] + C[i-1][1] and k >= 2:   # 选两个英雄凑羁绊

                dp[k][i][j] = max(dp[k][i][j],V[i-1][0]+V[i-1][1]+V[i-1][2]+dp[k-2][i-1][j-C[i-1][0]-C[i-1][1]])

print(dp[-1][-1][-1])
发表于 2025-04-15 21:13:38 回复(0)
从C++改写的,过不了。
n, C, m = map(int, input().split())
costs = [0] * (n + 1)
fightings = [0] * (n + 1)
connections = [0] * (n + 1)
unionfights = [0] * (n + 1)

for i in range(1, n + 1):
    costs[i], fightings[i] = map(int, input().split())

for _ in range(m):
    u, v, w = map(int, input().split())
    if u > v:
        u, v = v, u
    connections[u] = v
    unionfights[u] = w

dp = [[0] * (C + 1) for _ in range(5)]  # dp[p][j]: 用p个物品,容量为j时的最大战斗力

for i in range(1, n + 1):
    k = connections[i]
    for p in range(4, 0, -1):
        if k == 0:
            for j in range(C, costs[i] - 1, -1):
                dp[p][j] = max(dp[p][j], dp[p - 1][j - costs[i]] + fightings[i])
        elif k > i:
            low_bound = min(costs[i], costs[k])
            for j in range(C, low_bound - 1, -1):
                if j - costs[i] >= 0:
                    dp[p][j] = max(dp[p][j], dp[p - 1][j - costs[i]] + fightings[i])
                if j - costs[k] >= 0:
                    dp[p][j] = max(dp[p][j], dp[p - 1][j - costs[k]] + fightings[k])
                if j - costs[i] - costs[k] >= 0 and p >= 2:
                    dp[p][j] = max(dp[p][j], dp[p - 2][j - costs[i] - costs[k]] +
                                   fightings[i] + fightings[k] + unionfights[i])

ans = max(dp[i][C] for i in range(5))
print(ans)

发表于 2025-04-07 22:10:36 回复(0)
Python一直过不了,最多过3个用例,实在想不到优化方法了,有没有大佬帮忙再优化一下
n, C, m = list(map(int, input().split()))
heromax = 4

baseinfo = []
for _ in range(n):
    baseinfo.append(list(map(int, input().split())))

pairsinfo = []
for _ in range(m):
    pairsinfo.append(list(map(int, input().split())))

pairsdict = dict()
for i in range(m):
    if pairsinfo[i][0] > pairsinfo[i][1]:
        pairsinfo[i][0], pairsinfo[i][1] = pairsinfo[i][1], pairsinfo[i][0]
    pairsdict[pairsinfo[i][0] - 1] = [pairsinfo[i][1] - 1, pairsinfo[i][2]]


def dpfind(info: list[list[int]]):
    dplist = [[0 for _ in range(C + 1)] for _ in range(heromax + 1)]
    for heroidx in range(n):
        for cmax in range(C, -1, -1):
            for heronum in range(heromax):
                herocost = info[heroidx][0]
                if herocost <= cmax:  # 如果这个英雄cost够低
                    newPower = info[heroidx][1] + dplist[heronum][cmax - herocost]
                    # print(dplist)
                    dplist[heronum + 1][cmax] = max(dplist[heronum + 1][cmax], newPower)
                    if heroidx in pairsdict.keys() and heronum < heromax - 1:
                        pairidx = pairsdict[heroidx][0]
                        paircost = info[pairidx][0]
                        if paircost + herocost <= cmax:
                            newPower = (
                                info[heroidx][1]
                                + info[pairidx][1]
                                + pairsdict[heroidx][1]
                                + dplist[heronum][cmax - herocost - paircost]
                            )
                            dplist[heronum + 2][cmax] = max(
                                dplist[heronum + 1][cmax], newPower
                            )

    return dplist[-1][-1]


print(dpfind(baseinfo))



发表于 2025-03-04 14:58:38 回复(2)