#P3009. MVP争夺战(100分)
-
1000ms
Tried: 263
Accepted: 58
Difficulty: 6
所属公司 :
华为od
-
算法标签>动态规划
MVP争夺战(100分)
题面描述
在星球争霸篮球赛对抗赛中,最大的宇宙战队希望每个人都能拿到 MVP ,MVP 的条件是单场最高分得分获得者。
可以并列所以宇宙战队决定在比赛中尽可能让更多队员上场,并且让所有得分的选手得分都相同。
然而比赛过程中的每 1 分钟的得分都只能由某一个人包揽。
思路
本题要求将给定的得分列表分配给尽可能多的队员,使得每个队员的得分相同。要达到这一目标,我们需要:
-
最大化队员数目:即找到最大的可能的 k,使得总得分可以被 k 整除,并且能够将得分分配给 k 个队员,每个队员的得分都等于总得分除以 k。
-
分割得分列表:检查是否可以将得分列表分割成 k 个子集,每个子集的和都等于目标得分 S=总得分/k。
具体步骤如下:
- 计算总得分 T。
- 从最大的可能的队员数 k=t 开始,依次递减。
- 对于每个 k,检查 T 是否能被 k 整除,即 S=T/k 是整数。
- 如果能整除,则尝试将得分列表分割成 k 个和为 S 的子集。
- 如果成功分割,则输出 S,因为我们从最大的 k 开始,S 会是最小的可能值。
由于输入规模较小(t≤50),可以使用回溯法进行子集划分。
cpp
#include <bits/stdc++.h>
using namespace std;
// 回溯函数尝试为每个子集分配得分
bool backtrack(vector<int>& nums, vector<int>& subsetSums, int target, int k, int start) {
if (k == 0) return true; // 所有子集都已成功分配
if (subsetSums[k - 1] == target) { // 当前子集已达到目标,开始分配下一个子集
return backtrack(nums, subsetSums, target, k - 1, 0);
}
for (int i = start; i < nums.size(); ++i) {
if (subsetSums[k - 1] + nums[i] > target) continue; // 剪枝:当前得分超过目标
if (i > start && nums[i] == nums[i - 1]) continue; // 去重
subsetSums[k - 1] += nums[i];
if (backtrack(nums, subsetSums, target, k, i + 1)) return true;
subsetSums[k - 1] -= nums[i];
}
return false;
}
// 检查是否可以将 nums 分割成 k 个子集,每个子集的和为 target
bool canPartitionKSubsets(vector<int>& nums, int k, int target) {
int n = nums.size();
vector<int> subsetSums(k, 0);
// 从最大的得分开始分配,先处理大的数可以更快剪枝
sort(nums.begin(), nums.end(), greater<int>());
// 如果最大的数超过目标,则不可能分配
if (nums[0] > target) return false;
return backtrack(nums, subsetSums, target, k, 0);
}
int main(){
int t;
cin >> t;
vector<int> p(t);
for(auto &x:p) cin >> x;
// 计算总得分
int total = accumulate(p.begin(), p.end(), 0);
// 从最大的可能队员数开始,寻找最小的 MVP 得分
for(int k = t; k >=1; --k){
if(total % k !=0) continue; // 总得分必须能被 k 整除
int target = total / k;
// 检查是否可以分割成 k 个子集,每个子集和为 target
if(canPartitionKSubsets(p, k, target)){
cout << target;
return 0;
}
}
return 0;
}
python
from typing import List
def can_partition(nums: List[int], k: int, target: int) -> bool:
nums.sort(reverse=True) # 先排序,优化剪枝
subsets = [0] * k
def backtrack(index):
if index == len(nums):
return True
current = nums[index]
for i in range(k):
if subsets[i] + current > target:
continue
if i > 0 and subsets[i] == subsets[i-1]:
continue
subsets[i] += current
if backtrack(index + 1):
return True
subsets[i] -= current
return False
return backtrack(0)
def main():
t, *rest = map(int, open(0).read().split())
p = rest[:t]
total = sum(p)
for k in range(t, 0, -1):
if total % k !=0:
continue
target = total // k
if can_partition(p, k, target):
print(target)
return
if __name__ == "__main__":
main()
java
import java.util.*;
public class Main {
public static boolean canPartition(int[] nums, int k, int target) {
Arrays.sort(nums);
// 从大到小排序
for(int i=0; i<nums.length/2; i++){
int temp = nums[i];
nums[i] = nums[nums.length-1-i];
nums[nums.length-1-i] = temp;
}
int[] subsets = new int[k];
return backtrack(nums, subsets, 0, target);
}
private static boolean backtrack(int[] nums, int[] subsets, int index, int target){
if(index == nums.length){
for(int i=0; i<subsets.length; i++) {
if(subsets[i] != target) return false;
}
return true;
}
for(int i=0; i<subsets.length; i++){
if(subsets[i] + nums[index] > target) continue;
if(i >0 && subsets[i] == subsets[i-1]) continue;
subsets[i] += nums[index];
if(backtrack(nums, subsets, index+1, target)) return true;
subsets[i] -= nums[index];
}
return false;
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
int[] p = new int[t];
for(int i=0; i<t; i++) p[i] = sc.nextInt();
int total = 0;
for(int num : p) total += num;
// 从最大的可能队员数开始,寻找最小的 MVP 得分
for(int k = t; k >=1; k--){
if(total % k !=0) continue;
int target = total / k;
if(canPartition(p, k, target)){
System.out.println(target);
return;
}
}
}
}
题目描述
在星球争霸篮球赛对抗赛中,最大的宇宙战队希望每个人都能拿到 MVP ,MVP 的条件是单场最高分得分获得者。
可以并列所以宇宙战队决定在比赛中尽可能让更多队员上场,并且让所有得分的选手得分都相同,
然而比赛过程中的每 1 分钟的得分都只能由某一个人包揽。
输入描述
输入第一行为一个数字 t ,表示为有得分的分钟数
1≤t≤50
第二行为 t 个数字,代表每一分钟的得分 p,
1≤p≤50
输出描述
输出有得分的队员都是 MVP 时,最少得 MVP 得分。
样例1
输入
9
5 2 1 5 2 1 5 2 1
输出
6
说明
样例解释 一共 4 人得分,分别都是 6 分
5+1,5+1,5+1,2+2+2