默罕默德的炸弹

xiaoxiao2021-02-28  149

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

思路:

题意是不能改变炸弹顺序,只能确定它们的分组,使制造出的炸弹拥有最大的威力和。

方便理解题意,那么先看下样例是怎么过的

5 9 8 2 1 6

一组数据有多种分法:

你可以分成1组,那么威力和就是只分成一组的威力(9-1)²=64。

也可以分成2组,如(5,9) (8,2,1,6)这样威力和是16+49=65,分成2组还有别的组合这里就不算了。

我们可以知道6个数 最多能分成6组(每个数为一组)。

样例的最优分组是 (5,9) (8,2) (1,6)。3组,这样威力和是16+35+25=77最大。

 

开始分析 :看上去,好像能用暴力,但是仔细分析就觉得不靠谱了。1000个数就有

C(0,999)+C(1,999)+C(2,999)+……+C(999,999)种可能。这就只能呵呵了。

换种思路:

有n个小炸弹 可以能分成i组(1<=i<=n)。

如果我们已经知道(1<=i<=n)dp[i][n]表示:n个小炸弹,分成i组的各种组合中,(威力和最大的那个组合)的(威力和)。如样例中dp[1][6]=64 . dp[3][6]=77.

那么我只要输出(1<=i<=n)中dp[i][n]最大的那个就行了。

  

那么现在的问题变成如何求dp[i][n].想到这里已经明白显然是个动态规划问题,要去想如何进行状态转移。

dp[i][n]讨论的是把n个数分成i组的问题。为了方便说明,继续拿样例讨论。

比如 5 9 8 2 1 6 求dp[3][6].此时我们已经算出最优解的情况是(5,9) (8,2) (1,6). 这时最后一组是(1,6)

但是一开始我不知道最优解的最后一组是6,还是(1,6),还是(2,1,6)等。

为什么要知道最后一组呢?

假设最后一组是6,那么问题就变成求5 9 8 2 1中分成2组的最大威力和了。

此时他的威力和是 dp[2][5]+v[6][6].      //假设我们已经知道v[i][j]代表下标i到j为一组的威力和.

同理一样如果最后一组是(1,6),那么问题就变成求5,9,8,2中分成2组的最大威力和。

此时他的威力和是dp[2][4]+v[5][6],

我们只要枚举这样所有的可能,就能找出最优解得到dp[3][6]。

我们知道,若最后一组知道,那么扣掉最后一组的数,假设还剩k个数,k显然不能等于n.

这k个数要分成i-1组显然k要大于i-1。那么i-1<=k<n.

此时已经可以推出转移方程:dp[i][j]=max(dp[i][j],dp[i-1][k]+v[k+1][j]); (i-1<=k<n)

剩下的把v[i][j]搞定就好了。

#include <cstdio> #include <algorithm> using namespace std; #define max(a,b) (((a)>(b))?(a):(b)) int n,a[1005],dp[1005][1005],v[1005][1005]; int main() { int i,j,k,res; int iMax,iMin; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&a[i]); } for(i=1;i<=n;i++) { iMax=iMin=a[i]; for(j=i;j<=n;j++) { if(a[j]>iMax) iMax=a[j]; if(a[j]<iMin) iMin=a[j]; v[i][j]=(iMax-iMin)*(iMax-iMin); } }//v[i][j]代表从下标i到j为一组的炸弹威力 //dp i=1; for(j=1;j<=n;j++) dp[1][j]=v[1][j]; // i>=2; for(i=2;i<=n;i++) { for(j=i;j<=n;j++) { for(k=i-1;k<j;k++) { dp[i][j]=max(dp[i][j],dp[i-1][k]+v[k+1][j]); } } } res=0; for(i=1;i<=n;i++) { res=max(res,dp[i][n]); } printf("%d\n",res); return 0; }

转载请注明原文地址: https://www.6miu.com/read-36841.html

最新回复(0)