HDU 4283 You Are the One 区间dp

题意:给定n(n<=100)个人,每一个有固定的权值D,现在n个人从1~n排成一排,第i个人第j个出列的时候的unhappiness值是Di* (j-1),现在有一个栈,
         可以暂时不让当前的人出列将其压栈,问怎样安排能使得sigma(unhappiness i)最小,求这个最小值。

题解:想dp[i][j]表示[i ,j]内的unhappiness最小值,枚举k(i<=k<j),有两种情况需要讨论:
          1 在k时刻[i , k]区间内的人全部在[k+1, j]区间内的人之前出列,且已经全部不在栈中,即[i , j]区间可以分为[i , k] , [k+1 ,j]两个完全相同的子问题,
             即dp[i][j] =MIN(dp[i][j] , dp[i][k] + dp[k+1][j] + (sum[j] – sum[i]) * (k – i +1));
          2 在k时刻[i , k]区间内的人全部在[k+1 , j]区间内的人之后出列,即[i , k]区间内的人全部需要进栈,所以出来的顺序是逆序的,需O(n2)预处理出against_order[i][j]
             表示[i , j]区间人逆序出来的unhappiness值,即dp[i][j] = MIN(dp[i][j] , dp[k+1][j] + against_order[i][k] + (sum[k]– sum[i-1]) * (j - k));

Sure原创,转载请注明出处。

#include <iostream>
#include <cstdio>
#include <memory.h>
#define MIN(a , b) ((a) < (b) ? (a) : (b))
using namespace std;
const int inf = 1 << 29;
const int maxn = 102;
int diao[maxn],sum[maxn],against_order[maxn][maxn],dp[maxn][maxn];
bool vis[maxn][maxn];
int n;

void read()
{
    memset(vis,false,sizeof(vis));
    sum[0] = 0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&diao[i]);
        sum[i] = sum[i-1] + diao[i];
        against_order[i][i] = 0;
    }
    return;
}

void make()
{
    for(int k=1;k<n;k++)
    {
        for(int i=1;i<n;i++)
        {
            int j = i + k;
            if(j > n) break;
            against_order[i][j] = against_order[i+1][j] + diao[i] * (j - i);
        }
    }
    return;
}

int dfs(int st,int end)
{
    if(st == end)
    {
        vis[st][end] = true;
        return dp[st][end] = 0;
    }
    if(vis[st][end])
    {
        return dp[st][end];
    }
    int res = inf;
    for(int i=st;i<end;i++)
    {
        res = MIN(res , dfs(st , i) + dfs(i+1 , end) + (sum[end] - sum[i]) * (i - st + 1));
        res = MIN(res , dfs(i+1 , end) + against_order[st][i] + (sum[i] - sum[st-1]) * (end - i));
    }
    vis[st][end] = true;
    return dp[st][end] = res;
}

int main()
{
    int cas;
    scanf("%d",&cas);
    for(int i=1;i<=cas;i++)
    {
        read();
        make();
        printf("Case #%d: %d\n",i,dfs(1,n));
    }
    return 0;
}

你可能感兴趣的:(ini,n2)