XMUTOJ-默罕默德的炸弹

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的炸弹数组

index012.....i....n-1
val546.....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<iostream>
#include<vector>

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<vector<int> > pre(n, vector<int>(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表格输出
	/*
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			printf("%d ", pre[i][j]);
		}
		printf("\n");
	}
	*/

	vector<int> 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("%d\n", dp[n - 1]);
	return 0;
}

如果还不清楚的话可以私信我

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值