Pangu and Stones HihoCoder - 1636 (ICPC 2017 北京 J) 區間dp

傳送門:https://hihocoder.com/problemset/problem/1636

題意:

給你n(<=100)堆石子的數量,再給你兩個數L,R(2<=L<=R<=n),表示你只能將連續的x(L<=x<=R)堆石子合併成爲一堆,費用爲這x堆石子數量的總數。求將這n堆石子合併成1堆的最小花費,如果不能合併成一堆輸出0。

思路:這題跟區間dp的入門很像,但是暴力枚舉[i,k][k+1,j]區間的同時還要考慮兩個子區間的石子堆數,這樣dp需要再加一維,直接枚舉的複雜度就成了O(n^5),果然TLE了,然後窩就自閉了三個小時。。。

發現其實只需要考慮其中一個子區間爲1堆,另一個子區間爲s堆的情況,因爲多堆也會被包含進狀態裏面。

dp[i][j][s]表示第i堆石子到第j堆石子合併成爲s堆石子的最小花費。則有:

dp[i][j][s+1]=min(dp[i][j][s+1],dp[i][k][s]+dp[k+1][j][1]);(1<=s+1<=j-i+1 , i<=k<j)

dp[i][j][1]=min(dp[i][j][1],dp[i][k][s]+dp[k+1][j][1]+sum[j]-sum[i-1]);(1<=L<=s+1<=min(j-i+1,R) , i<=k<j)

 

dp[i][j][s+1]=min(dp[i][j][s+1],dp[i][k-1][1]+dp[k][j][s]);(1<=s+1<=j-i+1 , i<k<=j)

dp[i][j][1]=min(dp[i][j][1],dp[i][k][s]+dp[k+1][j][1]+sum[j]-sum[i-1]);(1<=L<=s+1<=min(j-i+1,R) , i<k<=j)

 

這樣時間複雜度就成了O(n^4),實際上還要除上一些常數,所以效率還是很高的。

代碼:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define mst(head,x,n) memset(head+1,x,n*sizeof(head[0]))
#define rep(i,a,b) for(register int i=(a);i<=(b);i++)
#define dep(i,a,b) for(register int i=(a);i>=(b);i--)
using namespace std;
const int maxn=2e2+5;
//const double pi=acos(-1.0);
//const double eps=1e-9;
//const ll mo=1e9+7;
int n,m,k,L,R;
int a[maxn],sum[maxn];
int ans,tmp,cnt;
int flag;
char s[maxn];
int as[maxn];
bool ok[maxn];
int dp[maxn][maxn][maxn];
template <typename T>
inline void read(T &X){
    X=0;int w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    if(w) X=-X;
}
int main(){
    srand(time(NULL));
    int T,cas=1;
    //read(T);
    //while(T--)
    while(scanf("%d%d%d",&n,&L,&R)!=EOF)
    {
        //read(n);read(L);read(R);
        ans=0; flag=0;
        rep(i,1,n){
            //read(a[i]);
            scanf("%d",&a[i]);
            //a[i]=rand()%1000+1;
            sum[i]=sum[i-1]+a[i];
        }
        rep(i,0,n)
        rep(j,0,n)
        rep(k,0,n) dp[i][j][k]=inf;
        rep(i,1,n) {
            dp[i][i][1]=0;
        }
        rep(len,2,n){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                for(int k=i;k<j;k++){
                    for(int s1=1;s1<=k-i+1;s1++){
                        dp[i][j][s1+1]=min(dp[i][j][s1+1],dp[i][k][s1]+dp[k+1][j][1]);
                        if(s1+1>=L&&s1+1<=R)
                        dp[i][j][1]=min(dp[i][j][1],dp[i][k][s1]+dp[k+1][j][1]+sum[j]-sum[i-1]);
                    }
                }
                for(int k=i+1;k<=j;k++){
                    for(int s2=1;s2<=j-k+1;s2++){
                        dp[i][j][s2+1]=min(dp[i][j][s2+1],dp[i][k-1][1]+dp[k][j][s2]);
                        if(s2+1>=L&&s2+1<=R)
                        dp[i][j][1]=min(dp[i][j][1],dp[i][k-1][1]+dp[k][j][s2]+sum[j]-sum[i-1]);
                    }
                }
            }
        }
        //cout<<n<<" "<<L<<" "<<R<<endl;
        if(dp[1][n][1]==inf) {
            puts("0");
        }
        else {
            printf("%d\n",dp[1][n][1]);
        }
    }
    return 0;
}

 

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