1. 程式人生 > >hihoCoder 1636 Pangu and Stones

hihoCoder 1636 Pangu and Stones

namespace post hoc hihocode 區間 spa mes col pre

hihoCoder 1636 Pangu and Stones

思路:區間dp.

狀態:dp[i][j][k]表示i到j區間合並成k堆石子所需的最小花費。

初始狀態:dp[i][j][j-i+1]=0

狀態轉移:

如果k等於1,dp[i][j][1]=min(dp[i][j][1],dp[i][k][s-1]+dp[k+1][j][1]+sum[j]-sum[i-1])(i<=k<j)

s從l到r,因為合並成一堆的時候是有堆數限制的

如果k大於1,dp[i][j][k]=min(dp[i][j][k],dp[i][s][k-1]+dp[s+1][j][1])(i<=s<j)

石子合並問題基本套路:先合並小區間,再合並大區間,所以第三維的s-1和1可以互換位置,因為無論怎樣,小區間的值都已經確定

代碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=105;
const int INF=0x3f3f3f3f;
int dp[N][N][N];
int a[N],sum[N];
int main(){
    ios::sync_with_stdio(
false); cin.tie(0); int n,l,r; while(cin>>n>>l>>r){ for(int i=1;i<=n;i++)cin>>a[i],sum[i]=sum[i-1]+a[i]; mem(dp,INF); for(int i=1;i<=n;i++){ for(int j=i;j<=n;j++) dp[i][j][j-i+1]=0; }
for(int d=1;d<=n;d++){ for(int i=1;i+d-1<=n;i++){ int j=i+d-1; for(int k=i;k<j;k++){ for(int s=l;s<=r;s++){ dp[i][j][1]=min(dp[i][j][1],dp[i][k][s-1]+dp[k+1][j][1]+sum[j]-sum[i-1]); } } for(int k=2;k<=n;k++){ for(int s=i;s<j;s++){ dp[i][j][k]=min(dp[i][j][k],dp[i][s][k-1]+dp[s+1][j][1]); } } } } if(dp[1][n][1]==INF)cout<<0<<endl; else cout<<dp[1][n][1]<<endl; } return 0; }

hihoCoder 1636 Pangu and Stones