HDU-4283-You Are the One

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了一次啊哈哈)

代码部分:

扫描二维码关注公众号,回复: 10168496 查看本文章
#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;
}
发布了112 篇原创文章 · 获赞 3 · 访问量 2643

猜你喜欢

转载自blog.csdn.net/qq_44624316/article/details/104897106