1. 程式人生 > >HDU 4283 You Are the One ——區間dp

HDU 4283 You Are the One ——區間dp

col set define 根據 單點 pre ems 直接 tps

參考了許多大佬 尤其是https://blog.csdn.net/woshi250hua/article/details/7973824這一篇 ,最後我再加一點我的見解。

大意是 給定一個序列,序列內的人有屌絲值Di,將這個序列進棧,第i個人如果是第k個出棧,那麽最後的屌絲總值增加Di * (k-1), 求一個出棧序列使得總屌絲值最小。

這一題用到了一個性質,如果第1個人確定了是第k個出棧,那麽第2~k個人一定在他之前出棧,而且k+1~n個人一定在他之後出棧。這個可以隨便拿紙模擬一下來得出結論。

然後區間劃分的思路就有了,枚舉一下k,處理出[l,r]區間l第k個彈出時的最小總屌絲值。最後dp[1][n][1]就是最終解。

代碼如下:

#include<iostream>
#include<string.h>
using namespace std;
#define INF (1<<29)
#define ll long long
ll dp[105][105][105],n,a[105],ans; 
ll solve(ll l,ll r,ll k)
{
    if(l>r) return 0; //無意義值直接返回 
    if(l==r) return a[l]*(k-1); //遞歸到單點,意味著該值意義為“第l個人第k個出場帶來的屌絲值” 
if(dp[l][r][k]!=INF) return dp[l][r][k]; //不為INF代表該值之前走到過,就不用再走了,直接返回該值 ll qian,hou,qiank,houk,now; // 根據之前的結論,我們把區間[l,r]分為三個部分 l、l+1~k、k+1~r for(int i=l;i<=r;i++) { houk=k+i-l+1;//該值houk表示遞歸區間k+1~r時帶入的k qiank=k+i-l;//該值qiank示第l號人出場的序號 qian=solve(l+1
,i,k);//該值qian表示遞歸區間l+1~i時返回的最優值 hou=solve(i+1,r,houk);//該值hou表示遞歸區間i+1~r時返回的最優值 now=a[l]*(qiank-1);//l號選手的屌絲值 dp[l][r][k]=min(dp[l][r][k],qian+hou+now); //更新最優值 } return dp[l][r][k]; } int main() { ll i,j,k,l,ans,t,n; //cout<<INF<<endl; cin>>t; l=0; while(t--) { l++; cin>>n; for(i=1;i<=n;i++) cin>>a[i]; for(i=1;i<=n;i++) for(j=1;j<=n;j++) for(k=0;k<=n;k++) dp[i][j][k]=INF;//提示這裏的INF比較大 不能用memset來賦值 不然會出問題 ans=solve(1,n,1); cout<<"Case #"<<l<<": "<<ans<<endl; } }

HDU 4283 You Are the One ——區間dp