hdu 4283 (區間dp)

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4283

題目大意:以下思路轉自(http://www.tuicool.com/articles/jyaQ7n)當中思路已經很明確

有n個男屌絲事先按1,2,3,,,,,,n的順序排好,每個人都有一個不開心值unhappy[i],如果第i個人第k個上臺找對象,那麼該屌絲男的不開心值就會爲(k-1)*unhappy[i],因爲在他前面有k-1個人嘛,導演爲了讓所有男屌的總不開心值最小,搞了一個小黑屋,可以通過小黑屋來改變男屌的出場順序

注意 :這個小黑屋是個棧,男屌的順序是排好了的,但是可以通過入棧出棧來改變男屌的出場順序

解題思路

dp[i][j]表示區間[i,j]的最小總不開心值

把區間[i,j]單獨來看,則第i個人可以是第一個出場,也可以是最後一個出場(j-i+1),也可以是在中間出場(1   ~  j-i+1)

不妨設他是第k個出場的(1<=k<=j-i+1),那麼根據棧後進先出的特點,以及題目要求原先男的是排好序的,那麼::

第  i+1  到 i+k-1  總共有k-1個人要比i先出棧,

第 i+k   到j 總共j-i-k+1個人在i後面出棧

舉個例子吧:

有5個人事先排好順序  1,2,3,4,5

入棧的時候,1入完2入,2入完3入,如果我要第1個人第3個出場,那麼入棧出棧順序是這樣的:

1入,2入,3入,3出,2出,1出(到此第一個人就是第3個出場啦,很明顯第2,3號人要在1先出,而4,5要在1後出)

這樣子, 動態轉移方程 就出來啦,根據第i個人是第k個出場的,將區間[i,j]分成3個部分

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

(sum[j]-sum[i+k-1])*k 表示 後面的 j-i-k+1個人是在i後面纔出場的,那麼每個人的不開心值都會加個 unhappy,sum[i]用來記錄前面i個人的總不開心值,根據題目,每個人的unhappy是個 累加的過程 ,多等一個人,就多累加一次

代碼:

include<iostream>
#include<cstdio>
#include<cstring>
#include<string>

using namespace std;
const long long inf=0x3f3f3f3f3f;
int value[150];
long long sum[150];
long long dp[150][150];
long long dfs(int l,int r)
{
    if(dp[l][r]!=-1) return dp[l][r];
    long long& ans=dp[l][r];
    if(l>=r) return 0;
    ans=inf;
    for(int i=1;i<=r-l+1;i++)
    {
        ans=min(ans,dfs(l+1,l+i-1)+dfs(l+i,r)+(i-1)*value[l]+(sum[r]-sum[l+i-1])*i);
    }
    return ans;
}
int main()
{
    int t,n;
    int cont=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++){scanf("%d",&value[i]);sum[i]=sum[i-1]+value[i];}
        memset(dp,-1,sizeof(dp));
        printf("Case #%d: %lld\n",cont++,dfs(1,n));
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章