#校赛后的第一篇题解
#ac后评价:
确实是区间dp的一道好题捏~
但是本题题解属实不多,且区间dp题目一如既往的较难理解(本人看原有代码属实是一点没看懂),写一篇题解讲一下我做此题的(正经)方法。
#题目描述及翻译:
传送门:
Problem - 4283 (hdu.edu.cn)https://acm.hdu.edu.cn/showproblem.php?pid=4283翻译:
有一列男孩,每个男孩有一个diaosi值 di(代码里面被用作lis i)当一个男孩第k位上台时,unhappiness值为k*(di),有一个小黑屋,可以将男孩放入来调整位置,小黑屋满足栈的特性(FILO),求可能的最小unhappiness值之和。
#题目解答:
此题可以通过小区间的结果推出大区间的结果,显然是使用区间dp,既然使用区间dp,核心就是转移方程。
设dp数组为dp[ i ][ j ]: 含义是以i开头, j 结尾的区间 unhappiness值的最小值。
首先先for循环枚举区间长度len(区间dp都这么写),之后枚举i(即为开头),结尾j = i + len
dp[i][j]的状态转移请看下图(实际是懒得写了)
(那个长得像u的东西是k,不要搞错了)
#ac代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 998244353;
int T;
int main()
{
cin>>T;
int cas = 1;
int dp[105][105];
int lis[105];
int sum[105];
while(T--)
{
int n;
cin>>n;
memset(lis,0,sizeof(lis));
memset(sum,0,sizeof(sum));
memset(dp,0,sizeof(dp));
for(int i = 1; i <= n; i++)
{
cin>>lis[i];
sum[i] = lis[i] + sum[i-1];
}
for(int i = 1; i <= n; i++)
{
for(int j = i+1; j <= n; j++)
{
dp[i][j] = INF;
}
}
for(int len = 1; len < n; len++)
{
for(int i = 1; i+len <= n; i++)
{
int j = i+len;
for(int k = i; k <= j; k++)
{
dp[i][j] = min(dp[i][j], dp[i+1][k] + dp[k+1][j] + (k-i)*lis[i] + (k-i+1)*(sum[j]-sum[k]));
}
}
}
cout<<"Case #"<<cas<<": "<<dp[1][n]<<endl;
cas++;
}
return 0;
}
完结撒花~