Description
炸弹是塔利班对付美军的武器之一。默罕默德在塔利班的主要任务是做炸弹。默罕默德所做的新型炸弹由若干个小炸弹组成,每个小炸弹有一个威力值,整个炸弹的威力值是组成这个炸弹的最大威力差的平方,即(max-min)^2,假设一个炸弹有5个小炸弹组成,威力分别为5 9 8 2 1,那么它的威力为(9-1)^2=64。
时间紧任务多默罕默德的师傅兼老爸老默罕默德又不在,默罕默德不敢调整小炸弹的顺序,只能确定它们的分组。请你帮助默罕默德确定小炸药的分组,使制造出的炸弹拥有最大的威力和。
Input
第一行有 1 个正整数N( 1 <= N <= 1000),表示有N个小炸弹。
第二行有N个数,其中第i个数Ai表示第i个小炸弹的威力值( 0 <= Ai <= 1000)。
Output
输出炸弹的威力和。
Sample Input
6 5 9 8 2 1 6
Sample Output
77
Source
思路:
把n个炸弹分为任意组,前提是炸弹顺序不能变,例如炸弹为1,2,3,4
那么可以分为{1},{2,3},{4}
或者{1,2},{3},{4}
说白话就是分为若干个连续的子序列
首先v2动态规划八字金句(看分析图,图中的某些部分看不懂我下面会一一解释)
第一假设有这样一个大小为n的炸弹数组
| index | 0 | 1 | 2 | ..... | i | .... | n-1 |
| val | 5 | 4 | 6 | ..... | 1 | .... | 3 |
当我们选择到第i个下标的炸弹时(后面的统统不考虑):
我们可以考虑有哪些情况?
第i个炸弹可以与前面若干个炸弹组合成一个连续的炸弹组
例如{i-2,i-1,i}这三个炸弹组成一个炸弹组
那么就有i+1种情况:
{i-1,i}
{i-2,i-1,i}
{i-3,i-2,i-1,i}
....
{0,1,2,....,i-2,i-1,i}
第二
看懂了上面的解释
我们就可以定义一下通项了,设dp[i]为【0-i】范围内组成炸弹威力最大的值
起调也出来了,我们要求的最终结果就是dp[n-1],表示【0-n-1】范围内组成炸弹威力的最大值
第三
继续第一步的分析,我们选择到第i个炸弹
有i+1种可能的情况,我们是否可以枚举每一种情况,然后取最大值,这个值是不是就是dp[i]的值,即【0-i】范围内组成炸弹威力的最大值
那么我们用一个变量j来辅助枚举
转移方程伪代码:
for( j 范围 [0,i] )
{
dp[i]=max(dp[i], dp[j-1]+pre[j][i]);
}
dp[j-1]表示0-j-1范围内组成炸弹的最大值,pre[j][i]表示j-i范围内组成炸弹的威力值
pre[i][j]数组需要我们提前预处理,表示的就是从下标i到下表j区间内炸弹的威力值
第四
到此为止
通项:dp[i]
出口:dp[0]=0
起调:dp[n-1]
转移:
dp[i]=max(dp[i],dp[j-1]+pre[j][i])
代码:
#include#include using namespace std; int a[1005]; int main() { //输入 int n; scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%d", &a[i]); vector > pre(n, vector (n, 0)); //pre预处理数组 下标表示从i到j区间内炸弹威力值 //例如i=1,j=1表示下标为1的炸弹单独成组的炸弹威力值为0 for (int i = 0; i < n; i++) { int max_v = a[i]; int min_v = a[i]; for (int j = i; j < n; j++) { if (a[j] > max_v)max_v = a[j]; if (a[j] < min_v)min_v = a[j]; pre[i][j] = (max_v - min_v) * (max_v - min_v); } } //pre表格输出 vector dp(n + 1, 0); dp[0] = 0; for (int i = 1; i < n; i++) { for (int j = 0; j <= i; j++) { //注意j的取值,当j=0时,j-1=-1会数组越界,手动判断一下 if (j == 0) dp[i] = max(dp[i], 0 + pre[j][i]); else dp[i]= max(dp[i], dp[j-1] + pre[j][i]); } } printf("%dn", dp[n - 1]); return 0; }
如果还不清楚的话可以私信我



