LOJ P10147 [NOI1995] 石子合并 LOJ P10148 [NOIP2006] 能量项链【区间DP入门】

这是两道区间 D P 的入门题。之所以写这篇题解大概还是因为很久没有写区间 D P 了有些生疏。

石子合并

由于是圆形放置所以肯定要拉成线性,就 × 2 即可。

然后先考虑最小值。

f [ i ] [ j ] 表示合并 i > j i + 1 j n + i 1 的最小代价。

那么根据区间 D P 的套路不难得到 S u m [ ] 表示前缀和:

f [ i ] [ j ] = m i n ( f [ i ] [ k ] + f [ k + 1 ] [ j ] + S u m [ j ] S u m [ i 1 ] )

i + 1 j n + i 1 i k j 1

最后再 O ( n ) 扫一遍答案即可,最大值处理类似。

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL Max=2e2+5;
const LL Inf=1e18;
LL N,Ans1=Inf,Ans2,Num[Max<<1],Sum[Max<<1],DP1[Max<<1][Max<<1],DP2[Max<<1][Max<<1];
int main(){
    LL I,J,K;
    scanf("%lld",&N);
    for(I=1;I<=N;I++){
        scanf("%lld",&Num[I]);Num[N+I]=Num[I];
    }
    for(I=1;I<=N*2;I++){
        Sum[I]=Sum[I-1]+Num[I];
    }
    for(I=2*N;I>=1;I--){
        for(J=I+1;J-I<N;J++){
            DP1[I][J]=Inf;
            for(K=I;K<J;K++){
                DP1[I][J]=min(DP1[I][J],DP1[I][K]+DP1[K+1][J]+Sum[J]-Sum[I-1]);
                DP2[I][J]=max(DP2[I][J],DP2[I][K]+DP2[K+1][J]+Sum[J]-Sum[I-1]);
            }
        }
    }
    for(I=1;I<=N;I++){
        Ans1=min(Ans1,DP1[I][I+N-1]);
        Ans2=max(Ans2,DP2[I][I+N-1]);
    }
    printf("%lld\n%lld",Ans1,Ans2);
    return 0;
}

能量项链

类似处理。

f [ i ] [ j ] 表示合并 i > j 的最大值。

f [ i ] [ j ] = m a x ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] + v [ i ] v [ j + 1 ] v [ k + 1 ] )

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL Max=1e3+5;
LL N,Ans,V[Max<<1],DP[Max<<1][Max<<1];
int main(){
    LL I,J,K;
    scanf("%lld",&N);
    for(I=1;I<=N;I++){
        scanf("%lld",&V[I]);V[I+N]=V[I];
    }
    for(I=2*N;I>=1;I--){
        for(J=I+1;J-I<N;J++){
            for(K=I;K<J;K++){
                DP[I][J]=max(DP[I][J],DP[I][K]+DP[K+1][J]+V[I]*V[K+1]*V[J+1]);
            }
        }
    }
    for(I=1;I<=N;I++){
        Ans=max(Ans,DP[I][I+N-1]);
    }
    printf("%lld",Ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/81412420