题解
题目大意,一队人排队上台表演,每个人有个值a[i],他第k个上场就会有a[i]*(k-1)的不愉快度,现在有个栈可以调整上台顺序,对于每个人可以选择进栈或者直接上台,在栈中的人可以随时上台,问不愉快度的最小总和
区间dp求解,d[i][j]表示区间[i, j]第i个前面没有人的情况下的最小代价,也就是只有区间[i, j]这些人任意安排顺序上场的最小代价
对于每个区间考虑将第一个人进栈,等后面的人都走了之后再出栈上台,转移为d[i][j]=min(d[i][j], d[i+1][j] + a[i] * (j - i))
a[i] * (j - i)是因为他要最后上场,额外的不愉快度为a[i]*(区间长度-1),由于转移的区间是内部的区间所以不会出现交叉进栈的情况
合并区间时枚举区间间断点k,转移为d[i][j] = min(d[i][j], d[i][k] + d[k + 1][j] + (k - i + 1) * (s[j] - s[k])),利用前缀和将后区间额外的不愉快度计算出来
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
#define fst first
#define sed second
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 110;
int a[MAXN], s[MAXN];
int d[MAXN][MAXN]; //区间[i, j]第i个前面没有人的情况下的最小代价
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int T;
cin >> T;
for (int ti = 1; ti <= T; ti++)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), s[i] = s[i - 1] + a[i]; //前缀和
memset(d, 0x3f, sizeof(d));
for (int i = 1; i <= n; i++) d[i][i] = 0; //单个人为0
for (int l = 1; l < n; l++)
for (int i = 1; i + l <= n; i++)
{
int j = i + l;
d[i][j] = min(d[i][j], d[i + 1][j] + a[i] * (j - i)); //尝试把第i个人进栈先让[i+1, j]上场
for (int k = i; k < j; k++)
d[i][j] = min(d[i][j], d[i][k] + d[k + 1][j] + (k - i + 1) * (s[j] - s[k]));
}
printf("Case #%d: ", ti);
cout << d[1][n] << endl;
}
return 0;
}

本文探讨了一种使用区间动态规划方法来解决特定排队问题的算法。该问题涉及一组表演者,每个人上台的顺序会影响其不愉快度。通过栈操作调整上台顺序,目标是最小化所有人的总不愉快度。文章详细解释了区间DP的思路和转移方程,并提供了AC代码实现。

92

被折叠的 条评论
为什么被折叠?



