HDU-4283-You Are the One
这道题区间dp。
今天在写区间dp的题目啦~
原以为写了一个模板题就懂了的样子。。
发现事实不是这样。。
题目大意:几个人排队。每个人都有一个不高兴值。如果某一个人的不高兴值是D,那么如果他是第K个人上场,那么他的前面有k-1个人,他的不高兴值是D*(K-1)
问怎样排队才可以使得总不高兴的代价最小
我转移方程说实话写了半天=-=
dp[i][j]定义为i~j的不高兴的值
我先开始考虑的时候有点迷。总是觉得i的前面还有人,j的后面还有人。然后我就卡在转移方程上面。。。
这个地方就是单纯考虑i~j,不用管其他的。啥都不用管。这样就比较好写了。
初始化还是INF,然后dp[i][i] = 0.这个毫无疑问就只有一个人,他的前面没有人,所以不高兴值为0.
我们还是需要求一下前缀和。sum[]保存
状态转移方程:
因为我们此时的顺序是不变的(sum[]按照输入的顺序存储的)
我们假设i是i~j中第k个上场的。那么i的前面有k-1个人。
我们现在此时的范围在i~j中!!!不要考虑其他的!!
这里的i相当于这个时候的第一个人。
所以我们需要从i+1之后选择k-1个人排在i的前面,使得i成为第k个上场的。
dp[i +1][i + k - 1]是我们前k-1个人的不高兴值。这个值跟当前是没有关系的,因为这个的dp又是自己内部自己的顺序,我们不需要管他内部的顺序是什么,就当作已经求出来了。
所以i此刻的不高兴值为a[i](k-1)
现在考虑第k+1上场的及后面。
这个时候的dp[i+k][j]是他自己求出来内部的排序所获得的不高兴值。(从第一个上场开始)
现在有k个人排在他的前面了。
我们应该加上他们的不高兴值。我们不是求了前缀和嘛。获得一下区间和就可以啦。
就是k(sum[j] - sum[i + k - 1])是新增加的不高兴值
所以状态转移方程:
dp[i][j] = min(dp[i][j], dp[i + 1][i + k - 1] + a[i](k-1)+ dp[i + k][j] + k(sum[j] - sum[i + k - 1]));
特别注意下标的处理。
枚举k的时候要考虑到第n个出场的情况。。(我在这里wa了一次啊哈哈)
代码部分:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e2 + 10;
const int INF = 1e9 + 10;
int sum[N];
int a[N];
int dp[N][N];
int cnt = 1;
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
scanf ("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
dp[i][i] = 0;
}
for (int len = 1; len < n; len++)
{
for (int i = 1; i <= n - len; i++)
{
int j = i + len;
dp[i][j] = INF;
for (int k = 1; k <= len + 1; k++)
{
dp[i][j] = min(dp[i][j], dp[i + 1][i + k - 1] + a[i] * (k - 1) + dp[i + k][j] + k * (sum[j] - sum[i + k - 1]));
}
}
}
cout << "Case #" << cnt++ << ": ";
cout << dp[1][n] << endl;
}
return 0;
}