pangu and stones(区间dp)

题意 :有 N 堆石子,每次能够合并连续的、大于等于 L 、小于等于 R 堆石子,代价是这些石子的个数和。问合并成一堆石子的代价最小值。
使用一个 dp [l][r][k] 记录 将区间 [ l,r ] 的石子合并为 k 堆需要的最小代价。用一个 d[ i ] 记录第 k 堆石子有几个石子
转移方程: dp ( l,r,k )=min{ dp (l,i,1)+ dp (i+1,r,k-1)},l<= i
                dp (l,r,1)=min{ dp ( l,r,x )}+(d[l]+…+d[r]),L<=x<=R


          //当时在现场赛的时候没推出来转移方程,胡乱分析了四个小时,甚至队员想出了dfs离散化之类的骚操作...然并卵还是没做出来然后打铁回家
#include 


using namespace std;
const int maxn=120,inf=1000000;

int dp[maxn][maxn][maxn],d[maxn],mi,ma;
int n;
int init()
{

    for(int i=1;i<=n;i++)
    {
        cin>>d[i];
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
            {
                dp[i][j][k]=-1;
            }
     for(int i=1;i<=n;i++)
    {
        dp[i][i][1]=d[i];
    }
}
int solve(int l,int r,int k)
{
    if(dp[l][r][k]==-2)return -2;
    if(l==r&&dp[l][r][k]!=-1)return 0;
    if(dp[l][r][k]!=-1)return dp[l][r][k];
    if(k==1)
    {int m=inf;
        if(l!=r+1)
        {

        for(int i=mi;i<=ma;i++)
        {
            int cur=solve(l,r,i);
            if(m>cur&&cur>=0){m=cur;}
        }

        }
        else m=0;
         if(m!=inf)

            for(int i=l;i<=r;i++)
        {
            m+=d[i];
        }

        else m=-2;
        dp[l][r][1]=m;
        return m;
    }
    int m=inf;
    for(int i=l;icur1+cur2){ if(l==i)cur1=0;if(i+1==r)cur2=0;  m=cur1+cur2;}
    }
    if(m>=inf){dp[l][r][k]=-2;return -2;}
    else dp[l][r][k]=m;
    return m;
}

int main()
{

    while(    cin>>n>>mi>>ma)
    {init();
    int cc=solve(1,n,1);
    if(cc<0)cc=0;
    cout<


你可能感兴趣的:(dp)