HihoCoder - 1636 J - Pangu and Stones (三维区间dp)

版权声明:本文为博主原创文章,转载请注明出处哦~ https://blog.csdn.net/a54665sdgf/article/details/82226957

题目链接

题意:给你一堆石子,每次只能归并连续的p-q个石子,归并的代价为归并的石子总数,求归并全部石子所需的最小代价,若无法归并则输出0。

解法:设dp[L][R][k]为将下标为L-R区间内的石子分成k堆所需的最小代价,则状态转移方程为:

dp(L,R,k)=\left\{\begin{matrix} min(dp(L,R,k),dp(L,M,1)+dp(M+1,R,i-1)-sum[L-1]+sum[R])(L<=M<R,p-1<=i<=q-1),k=1\\ min(dp(L,R,k),dp(L,M,1)+dp(M+1,R,k-1))(L<=M<R),k>=2\end{matrix}\right.

考虑递归边界:

(1)R-L+1=k,此时石子堆数即为目标堆数,代价为0。

(2)p<=R-L+1<=q,k=1,此时将所有石子合并即可,代价为L~R的石子总数。

(3)L-R+1<p,此时无法合并石子,代价为INF(无穷)。

打训练赛的时候想到了,但是当时从k=1推回k=p~q的时候懵了,没有勇气写下去。快结束的时候我决定试一下,然后因为bug没有A出来。当时应该把所有的dp值输出一下看看结果,debug能力还需加强。

赛后改对的代码:

#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>

using namespace std;
const int N=100+10;
const int INF=0x3f3f3f3f;
int n,p,q,d[N][N][N],vis[N][N][N],a[N],sum[N];

int dp(int L,int R,int k)
{
    if(R-L+1==k)return 0;
    if(R-L+1<=q&&R-L+1>=p&&k==1)return sum[R]-sum[L-1];
    if(R-L+1<p)return INF;
    if(vis[L][R][k])return d[L][R][k];
    if(k==1)
    {
        for(int i=p; i<=q; ++i)
            for(int M=L; M<R; ++M)
                d[L][R][k]=min(d[L][R][k],dp(L,M,1)+dp(M+1,R,i-1)-sum[L-1]+sum[R]);
    }
    else
    {
        for(int M=L; M<R; ++M)
            d[L][R][k]=min(d[L][R][k],dp(L,M,1)+dp(M+1,R,k-1));
    }
    vis[L][R][k]=1;
    return d[L][R][k];
}

int main()
{
    //freopen("i.txt","r",stdin);
    while(scanf("%d%d%d",&n,&p,&q)==3)
    {
        for(int i=0; i<=n; ++i)
            for(int j=0; j<=n; ++j)
                for(int k=0; k<=q; ++k)
                {
                    d[i][j][k]=INF;
                    vis[i][j][k]=0;
                }
        for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
        sum[0]=0;
        for(int i=1; i<=n; ++i)sum[i]=sum[i-1]+a[i];
        printf("%d\n",dp(1,n,1)==INF?0:dp(1,n,1));
    }
    return 0;
}
//

猜你喜欢

转载自blog.csdn.net/a54665sdgf/article/details/82226957