一维的背包,用dp[i] 表示前i位数的最大权值,sum[i]表示前i位数的总和。
转移方程为dp[i] = max( dp[i] , dp[j]+(sum[i]-sum[j])*(i-j) ),并且要分两种情况,也就是单调增和单挑减的情况讨论。
| ||
Accepted : 9 | Submit : 21 | |
Time Limit : 1000 MS | Memory Limit : 65536 KB |
题目描述小板有很多卡片,每个卡片上都有一个唯一的数字。某天,小板的哥哥--大板想和小板玩一个游戏。大板将卡片排列在桌上,形成一排,然后要求小板将其分成若干组,但是不能调换卡片的顺序。每组卡片上的数字和乘以卡片数量和就为这组卡片的分数,将每组卡片的分数相加得到总分。大板要求小板得到最多的分数并且每组卡片的上的数字必须是单调的,不然就不带他去公园玩。小板思索很久无法得到结果,所以向你求助。请你帮助小板得到最大的分数。 输入多组样例,每组样例有一行非负整数。第一个为卡片个数n,n<=1000,接下来为n个卡片数字,每个数字不超过100。 输出对于每组样例,输出最大的分数。 样例输入4 2 4 8 3 4 2 3 2 1 样例输出45 20 Sourceloying |
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
int n;
int num[1005];
int dp[1005],sum[1005];
int main()
{
while( scanf("%d",&n) != EOF ){
sum[0] = 0;
for( int i=1 ; i<=n ; i++ ){
scanf("%d",&num[i]);
sum[i] = sum[i-1]+num[i];
}
memset( dp , 0 , sizeof(dp) );
for( int i=1 ; i<=n ; i++ ){
dp[i] = dp[i-1] + num[i];
int j = i-2;
while( j>=0 && num[j+1] < num[j+2] ){
dp[i] = max( dp[i] , dp[j]+(sum[i]-sum[j])*(i-j) );
j--;
}
j = i-2;
while( j>=0 && num[j+1] > num[j+2] ){
dp[i] = max( dp[i] , dp[j]+(sum[i]-sum[j])*(i-j) );
j--;
}
}
printf("%d\n",dp[n]);
}
return 0;
}