#P3243. 查找充电设备组合(200分)
-
1000ms
Tried: 67
Accepted: 26
Difficulty: 2
所属公司 :
华为od
查找充电设备组合(200分)
题面描述
在某个充电站中,有 n 个充电设备,每个设备具有特定的输出功率,可以通过任意组合这些设备来获得不同的总输出功率,形成一个功率集合 P。现在需要找出这个集合中最接近充电站最大输出功率 pmax 的元素,且该元素必须小于或等于 pmax。如果所有组合的输出功率都大于 pmax,则输出 0。输入包括充电设备个数、各设备的输出功率和最大输出功率,输出为最优元素
思路
经典的01背包问题,将pmax看作是背包最大容量,每个物品的输出功率看作物品的重量和价值。
问题本质分析
该问题实际上是一个经典的 0-1 背包问题,以下是对其本质的详细分析:
-
问题描述:
- 我们有 n 个充电设备,每个设备的输出功率可以看作是物品的重量和价值。
- 充电站的最大输出功率 pmax 相当于背包的最大容量。
- 我们的目标是找到一个充电设备的组合,使得其总输出功率尽可能接近但不超过 pmax。
-
决策变量:
- 每个设备可以选择是否被使用(放入背包),即每个设备对应一个二元决策:选择使用(1)或不使用(0)。
-
状态表示:
- 使用一个布尔型数组
dp来记录是否可以用设备组合出某个特定的输出功率。 dp[i]表示是否存在设备组合的总输出功率为 i。
- 使用一个布尔型数组
-
状态转移:
- 从小到大更新
dp数组:对于每一个设备功率,从 pmax 开始,向下迭代,更新当前能达到的输出功率。 - 这一过程确保了在更新时不重复使用同一个设备功率。
- 从小到大更新
-
边界条件:
- 初始状态下,
dp[0] = true,表示不使用任何设备总功率为 0 是可行的。 - 所有其他
dp[i]初始为false,表示未确定。
- 初始状态下,
-
最终求解:
- 从
p_{max}开始向下查找第一个为true的dp值,即为最接近且不超过 pmax 的总输出功率。 - 如果没有找到合适的组合,则输出 0。
- 从
cpp
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n;
cin >> n;
vector<int> powers(n);
for(int &power : powers){
cin >> power;
}
int p_max;
cin >> p_max;
// 创建一个布尔型DP数组,dp[i]表示是否存在某个子集的总和为i
vector<bool> dp(p_max + 1, false);
dp[0] = true; // 总和为0总是可以实现(空集)
for(int power : powers){
// 从后往前遍历,避免重复使用同一个元素
for(int j = p_max; j >= power; --j){
if(dp[j - power]){
dp[j] = true;
}
}
}
// 从p_max开始向下查找第一个为true的值
for(int i = p_max; i >= 0; --i){
if(dp[i]){
cout << i;
return 0;
}
}
// 如果没有任何子集满足条件,输出0
cout << 0;
return 0;
}
python
def main():
n = int(input())
powers = list(map(int, input().split()))
p_max = int(input())
# 创建一个布尔型DP数组,dp[i]表示是否存在某个子集的总和为i
dp = [False] * (p_max + 1)
dp[0] = True # 总和为0总是可以实现(空集)
for power in powers:
# 从后往前遍历,避免重复使用同一个元素
for j in range(p_max, power - 1, -1):
if dp[j - power]:
dp[j] = True
# 从p_max开始向下查找第一个为True的值
for i in range(p_max, -1, -1):
if dp[i]:
print(i)
return
# 如果没有任何子集满足条件,输出0
print(0)
if __name__ == "__main__":
main()
java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] powers = new int[n];
for (int i = 0; i < n; i++) {
powers[i] = scanner.nextInt();
}
int p_max = scanner.nextInt();
// 创建一个布尔型DP数组,dp[i]表示是否存在某个子集的总和为i
boolean[] dp = new boolean[p_max + 1];
dp[0] = true; // 总和为0总是可以实现(空集)
for (int power : powers) {
// 从后往前遍历,避免重复使用同一个元素
for (int j = p_max; j >= power; j--) {
if (dp[j - power]) {
dp[j] = true;
}
}
}
// 从p_max开始向下查找第一个为true的值
for (int i = p_max; i >= 0; i--) {
if (dp[i]) {
System.out.println(i);
return;
}
}
// 如果没有任何子集满足条件,输出0
System.out.println(0);
}
}
题目内容
某个充电站,可提供 n 个充电设备,每个充电设备均有对应的输出功率。
任意个充电设备组合的输出功率总和,均构成功率集合 P 的 1 个元素。
功率集合 P 的最优元素,表示最接近充电站最大输出功率 pmax 的元素。
输入描述
输入为 3 行:
- 第 1 行为充电设备个数 n
- 第 2 行为每个充电设备的输出功率
- 第 3 行为充电站最大输出功率 pmax
输出描述
功率集合 P 的最优元素
备注
- 充电设备个数 0<n<=1000
- 最优元素必须小于或等于充电站最大输出功率 pmax<=1000
样例1
输入
4
50 20 20 60
90
输出
90
说明
当充电设备输出功率50、20、20组合时,其输出功率总和为90,最接近充电站最大充电输出功率,因此最优元素为90。
样例2
输入
2
50 40
30
输出
0
说明
所有充电设备的输出功率组合,均大于充电站最大充电输出功率30,此时最优元素值为0。