洛谷题解:P12207 [蓝桥杯 2023 国 Python B] 划分

题目描述

把给定的 40 40 40 个数分成两组,定义权值为组内所有元素的和,求两组权值的积最大是多少。

思路

先用背包 DP 求出两组的最优解(贪心的想法,当每组权值接近 40 40 40 个数的和的一半,积就最大),再求出乘积。

实现方法

d p j dp_j dpj 为第一组的权值能否为 j j j。所以遍历 a a a 的每个元素,遍历 a i − 1 a_i-1 ai1 40 40 40 个数的和的一半,若发现 d p j − a i dp_{j-a_i} dpjai 成立,则 d p j dp_j dpj 成立。因为 d p j dp_j dpj 可以通过 d p j − a j dp_{j-a_j} dpjaj 增加 a j a_j aj 得到。

具体实现代码

  • c++。
#include
using namespace std;
int a[]={5160,9191,6410,4657,7492,1531,8854,1253,4520,9231,
1266,4801,3484,4323,5070,1789,2744,5959,9426,4433,
4404,5291,2470,8533,7608,2935,8922,5273,8364,8819,
7374,8077,5336,8495,5602,6553,3548,5267,9150,3309};
bool dp[1000001];
long long sum,maxn,p;
int main(){
    //计算40个数的和的一半
	for(int i=0;i<40;i++)
		sum+=a[i];
	sum/=2;
    dp[0]=1;
    //DP
	for(int i=0;i<40;i++)//遍历a的每个元素
		for(int j=sum;j>=a[i];j--)
			if(dp[j-a[i]]) dp[j]=1;//若发现 $dp_{j-a_i}$ 成立,则 $dp_j$ 成立
	for(int i=sum;i>=0;i--)//贪心,离40个数的和的一半越近,乘积越大
		if(dp[i]){
            //发现最优解就赋值和跳出
			maxn=i;
			break;
		}
	p=maxn*(sum*2-maxn);//计算乘积
	cout<<p;//输出
	return 0;//完结散花
}
  • python。
a = [5160, 9191, 6410, 4657, 7492, 1531, 8854, 1253, 4520, 9231,
     1266, 4801, 3484, 4323, 5070, 1789, 2744, 5959, 9426, 4433,
     4404, 5291, 2470, 8533, 7608, 2935, 8922, 5273, 8364, 8819,
     7374, 8077, 5336, 8495, 5602, 6553, 3548, 5267, 9150, 3309]

sum_total = sum(a) 
dp = [False] * (sum_total + 1)
dp[0] = True
for num in a:
    for j in range(sum_total, num - 1, -1):
        if dp[j - num]:
            dp[j] = True
maxn = 0
for i in range(sum_total, -1, -1):
    if dp[i]:
        maxn = i
        break
p = maxn * (sum_total * 2 - maxn)
print(p)

给个赞再走呗。
原文链接

你可能感兴趣的:(题解,蓝桥杯)