您的位置:首页 > 其它

HDU4283 You Are the One

2017-07-19 17:11 369 查看
The TV shows such as You Are the One has been very popular. In order to meet the need of boys who are still single, TJUT hold the show itself. The show is hold in the Small hall, so it attract a lot of boys and girls. Now there are
n boys enrolling in. At the beginning, the n boys stand in a row and go to the stage one by one. However, the director suddenly knows that very boy has a value of diaosi D, if the boy is k-th one go to the stage, the unhappiness of him will be (k-1)*D, because
he has to wait for (k-1) people. Luckily, there is a dark room in the Small hall, so the director can put the boy into the dark room temporarily and let the boys behind his go to stage before him. For the dark room is very narrow, the boy who first get into
dark room has to leave last. The director wants to change the order of boys by the dark room, so the summary of unhappiness will be least. Can you help him? 

Input  The first line contains a single integer T, the number of test cases.  For each case, the first line is n (0 < n <= 100) 

  The next n line are n integer D1-Dn means the value of diaosi of boys (0 <= Di <= 100) 

Output  For each test case, output the least summary of unhappiness . 

Sample Input
2
  
5
1
2
3
4
5

5
5
4
3
2
2


Sample Output
Case #1: 20
Case #2: 24


题意:嗯就是说给你n个点,每个点有一个权值,n个点会按照顺序出列,每个点第k个出列,花费为(k-1)*权值。但是我们有一个辅助工具,也就是一个栈,可以暂时把当前点压进栈,暂时不出列。问你能获得的最小花费是多少。

数据量是100.每个人出列顺序其实看以看成是向一个区间插入。

我们设dp[i][j]表示i-j这个区间的最小花费,那么考虑第i个人,它可以第一个。。。第j-i+1个上。

所以我们枚举插入的位置k,那么就会有:

dp[i][j] = 

1.左区间的代价dp[i+1][k] 加上

2.num[i]*(k-i)它自己的花费 加上 

3.右区间的花费dp[k+1][j] + (k-i+1)*(sum[j] - sum[k])这里为什么会加上后面一块,因为右区间这部分相当于是向右平移了k-i+1个位置,前面多了k-i+1个人。

然后看代码应该就懂了:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <time.h>

using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
const int MAXN = 100+7;
int n;
int num[MAXN];
int sum[MAXN];
int dp[MAXN][MAXN];

int main()
{
int t;
scanf("%d",&t);
int ca = 0;
while(t--)
{
scanf("%d",&n);
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)
for(int j = i+1; j <= n; ++j)dp[i][j] = inf;

for(int i = n; i >= 1; --i)
for(int j = i; j <= n; ++j)
for(int k = i; k <= j; ++k)
{
dp[i][j] = min(dp[i][j],dp[i+1][k] + num[i]*(k-i) + dp[k+1][j] + (k-i+1)*(sum[j] - sum[k]));
}
printf("Case #%d: %d\n",++ca,dp[1]
);
}
return 0;
}


嗯,区间dp感觉不是很容易建模,不过100基本就是带有k的3重循环,1000的数据基本就是两重循环的dp。
关于怎么看出是区间dp,我觉得还是要做题总结才行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  区间dp