題目鏈接: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;
}