HDU3506 Monkey Party【区间DP】

题目链接: HDU3506 Monkey Party

题意:类似于环形合并石子,合并两堆石头的代价是两堆石子的数量和,问将所有石子合并的最小代价;

分析:dp[i][j]表示区间[i,j]的最小代价,p[i][j]表示区间[i,j]的石子个数,加入了四边形不等式优化,s[i][j]表示区间[i,j]的最佳断点;

【四边形不等式优化】

当a<b<=c<d时,如果满足f[a][c]+f[b][d]<=f[b][c]+f[a][d],f就满足四边形不等式,此时最佳断点s[i][j]就满足性质:

s[i][j-1]<=s[i][j]<=s[i+1][j]

这样原本枚举区间起点和断点的n*n就优化成n

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=2007;
int dp[maxn][maxn],s[maxn][maxn],p[maxn][maxn],a[maxn];
int n,ans;
void rua()
{
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n]=a[i];
    memset(dp,INF,sizeof(dp));
    memset(s,0,sizeof(s));
    for(int i=1;i<=n+n;i++)
    {
        dp[i][i]=0;
        s[i][i]=i;
        p[i][i]=a[i];
    }
    for(int i=1;i<n;i++)//区间长度
        for(int j=1;i+j<2*n;j++)//区间起点
            for(int k=s[j][i+j-1];k<=s[j+1][i+j];k++)
            {
                int tmp=p[j][k]+p[k+1][i+j];
                if(dp[j][i+j]>dp[j][k]+dp[k+1][i+j]+tmp)
                {
                    p[j][i+j]=tmp;
                    dp[j][i+j]=dp[j][k]+dp[k+1][i+j]+tmp;
                    s[j][i+j]=k;
                }
            }
    ans=INF;
    for(int i=1;i<=n+1;i++) ans=min(ans,dp[i][i+n-1]);
    printf("%d\n",ans);
}
int main()
{
    while(~scanf("%d",&n)) rua();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43813163/article/details/102554453