#P4551. 第3题-测试用例执行策略
-
1000ms
Tried: 15
Accepted: 0
Difficulty: 7
所属公司 :
华为
时间 :2026年1月21日-非AI方向(通软&嵌软&测试&算法&数据科学)
-
算法标签>动态规划
第3题-测试用例执行策略
No testdata at current.
解题思路
这是一个带额外约束的 0/1 背包问题。
- 每个测试用例只能选一次:典型 0/1 背包
- 总执行时间不能超过 T:背包容量是时间
- 若 t[i] > 30,则为“超长时间用例”,被选中的超长用例数量不超过 m:再加一维“超长数量”限制
- 目标:最大化覆盖测试点总数(价值)
设 dp[j][k] 表示:已选择 j 个超长用例、总时间为 k 时,能获得的最大测试点数量(不可达为 -1)。
对每个用例 (time=w, points=v):
-
long = 1若w > 30否则0 -
进行倒序转移(避免重复选同一用例):
dp[j][k] = max(dp[j][k], dp[j-long][k-w] + v)
最终答案是所有 dp[j][k](0≤j≤m,0≤k≤T)的最大值;允许一个都不选,答案可为 0。
复杂度分析
- 时间复杂度:O(n * m * T)
- 空间复杂度:O(m * T)
在数据范围内可通过。
代码实现
import sys
def max_points(n, T, m, items):
# dp[j][k]:用 j 个超长用例、时间 k 的最大测试点,不可达为 -1
dp = [[-1] * (T + 1) for _ in range(m + 1)]
dp[0][0] = 0 # 什么都不选
for w, v in items:
long_cnt = 1 if w > 30 else 0 # 是否为超长用例
# 倒序枚举,保证 0/1(每个用例最多选一次)
for j in range(m, long_cnt - 1, -1):
row = dp[j]
prev = dp[j - long_cnt]
for k in range(T, w - 1, -1):
if prev[k - w] != -1:
cand = prev[k - w] + v
if cand > row[k]:
row[k] = cand
ans = 0
for j in range(m + 1):
best = max(dp[j])
if best > ans:
ans = best
return ans
def main():
data = sys.stdin.read().strip().split()
if not data:
return
it = iter(data)
n = int(next(it))
T = int(next(it))
m = int(next(it))
items = []
for _ in range(n):
w = int(next(it))
v = int(next(it))
items.append((w, v))
print(max_points(n, T, m, items))
if __name__ == "__main__":
main()
#include <bits/stdc++.h>
using namespace std;
// 题面功能:带“超长用例数量限制”的 0/1 背包
int maxPoints(int n, int T, int m, const vector<pair<int,int>>& items) {
// dp[j][k]:用 j 个超长用例、时间 k 的最大测试点,不可达为 -1
vector<vector<int>> dp(m + 1, vector<int>(T + 1, -1));
dp[0][0] = 0; // 什么都不选
for (auto [w, v] : items) {
int longCnt = (w > 30) ? 1 : 0; // 是否为超长用例
// 倒序枚举,保证 0/1(每个用例最多选一次)
for (int j = m; j >= longCnt; --j) {
for (int k = T; k >= w; --k) {
if (dp[j - longCnt][k - w] != -1) {
dp[j][k] = max(dp[j][k], dp[j - longCnt][k - w] + v);
}
}
}
}
int ans = 0;
for (int j = 0; j <= m; ++j) {
for (int k = 0; k <= T; ++k) {
ans = max(ans, dp[j][k]);
}
}
return ans;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, T, m;
cin >> n >> T >> m;
vector<pair<int,int>> items(n);
for (int i = 0; i < n; ++i) {
int t, p;
cin >> t >> p;
items[i] = {t, p};
}
cout << maxPoints(n, T, m, items) << "\n";
return 0;
}
import java.io.*;
import java.util.*;
public class Main {
// 题面功能:带“超长用例数量限制”的 0/1 背包
static int maxPoints(int n, int T, int m, int[] w, int[] v) {
// dp[j][k]:用 j 个超长用例、时间 k 的最大测试点,不可达为 -1
int[][] dp = new int[m + 1][T + 1];
for (int j = 0; j <= m; j++) Arrays.fill(dp[j], -1);
dp[0][0] = 0; // 什么都不选
for (int i = 0; i < n; i++) {
int time = w[i];
int points = v[i];
int longCnt = (time > 30) ? 1 : 0; // 是否超长
// 倒序枚举,保证每个用例最多选一次
for (int j = m; j >= longCnt; j--) {
for (int k = T; k >= time; k--) {
if (dp[j - longCnt][k - time] != -1) {
int cand = dp[j - longCnt][k - time] + points;
if (cand > dp[j][k]) dp[j][k] = cand;
}
}
}
}
int ans = 0;
for (int j = 0; j <= m; j++) {
for (int k = 0; k <= T; k++) {
if (dp[j][k] > ans) ans = dp[j][k];
}
}
return ans;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
String first = br.readLine();
if (first == null || first.trim().isEmpty()) return;
st = new StringTokenizer(first);
int n = Integer.parseInt(st.nextToken());
int T = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
int[] w = new int[n];
int[] v = new int[n];
for (int i = 0; i < n; i++) {
st = new StringTokenizer(br.readLine());
w[i] = Integer.parseInt(st.nextToken());
v[i] = Integer.parseInt(st.nextToken());
}
System.out.println(maxPoints(n, T, m, w, v));
}
}
题目内容
执行测试用例时,需要在有限的时间内尽可能多地覆盖测试点。
已知:
-
共有 n 个测试用例,第 i 个测试用例的执行时间为 t[i] 分钟,覆盖的测试点数量为 p[i] 个
-
每个用例只能执行一次,每个用例覆盖的测试点不同
-
如果一个用例的执行时间超过 30 分钟,则属于超长时间用例,执行的所有超长时间用例数不超过 m
请问在限定的时间 T 内,执行的用例所能覆盖的最大测试点数量。
输入描述
第 1 行:n T m,代表 n 个测试用例,范围 [1,100],最大执行时长为 T,范围 [1,5000];最大超长时间用例数为 m,范围 [1,100]
第 2 行:t[0] p[0],代表第 1 个用例的执行时间和测试点数量,t[i] 范围 [1,60],p[i] 范围 [1,1000]
第 n+1 行:t[n−1] p[n−1],代表第 n 个用例的执行时间和测试点数量,t[i] 范围 [1,60],p[i] 范围 [1,1000]
输出描述
第1行:k,输出最大的测试点覆盖数量,可以是0
样例1
输入
3 50 0
35 5
40 10
50 15
输出
0
说明
输入表示:n=3,T=50,m=0 所有用例均是超长时间用例,不能选择,输出0
样例2
输入
3 10 1
15 5
20 10
25 15
输出
0
说明
输入表示:n=3,T=10,m=1 所有用例时间均超过最大时间,输出0
样例3
输入
4 100 1
20 50
35 60
25 30
40 70
输出
150
说明
输入表示:n=4,T=100,m=1 选择用例0,2,3,总时间为20+25+40=85<100,超长用例1<=1,最大测试点数量50+30+70=150