You Are the One HDU - 4283 区间dp

题意:有一队人排队,每个人焦虑因数di,每个等前面(k-1)个人的焦虑度为di*(k-1),问给你重新排序,最小焦虑度为多少。

思路:区间dp

该状态转移方程还是令人焦灼的,假设把所有人分成俩区间,一个[i+1,k],一个[k+1,j](i+1≤k<j)

如果d[i]先进去,则后面的焦灼度增加量为dp[i+1][k]*(d[i]*(k-1))+dp[k+1][j]*((k + 1 - i) * (sum[j] - sum[k]));(其中sum代表的是从k到j总的焦灼度和)

于是就有了个状态转移方程:

dp[i][j] = min(dp[i][j], dp[i+1][k]+d[i]*(k-i) + dp[k + 1][j]+(k + 1 - i) * (sum[j] - sum[k]));

废话不多说,直接进入代码环节

#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
using namespace std;
#define ll long long
#define N 205
#define rep(i,l,r) for(i=l;i<=r;i++)
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
#define eps 0.00000001//偏差值1e8
#define pi acos(-1.0)//高精度圆周率
const int maxp = 1010;                    //点的数量
int a[N];
int dp[N][N];
int w[N];
int sum[N];
int main()
{
    int i, j, k;
    int n, ret = 0, m, maxn = 0, count = 0;
    int t, x,y, len;
    cin >> t;
    while (t--)
    {

        count++;
        cin >> n;
        rep(i, 1, n)
        {
            cin >> a[i];
            sum[i] = sum[i - 1] + a[i];
        }
        rep(i, 0, n)
            rep(j, i + 1, n)
            dp[i][j] = INF;
        rep(len, 1, n)
        {
            rep(i, 1, n)
            {
                j = i + len - 1;
                if (j > n)break;
                rep(k, i, j)
                {
                    dp[i][j] = min(dp[i][j], dp[i+1][k]+a[i]*(k-i) + dp[k + 1][j]+(k + 1 - i) * (sum[j] - sum[k]));
                }
                
            }
        }
        printf("Case #%d: %d\n", count, dp[1][n]);
    }
}
        

    

 

posted @ 2020-04-11 16:08  ch_hui  阅读(130)  评论(0编辑  收藏  举报