区间dp

区间dp 一般格式为“枚举中间点”

即dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+fuckuniverse);

比较经典的问题就是合并石子

设有N堆沙子排成一排,其编号为1,2,3,…,N(N<=300)。每堆沙子有一定的数量,可以用一个整数来描述,现在要将这N堆沙子合并成为一堆,每次只能合并相邻的两堆,合并的代价为这两堆沙子的数量之和,合并后与这两堆沙子相邻的沙子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同,如有4堆沙子分别为 1  3  5  2 我们可以先合并1、2堆,代价为4,得到4 5 2 又合并 1,2堆,代价为9,得到9 2 ,再合并得到11,总代价为4+9+11=24,如果第二步是先合并2,3堆,则代价为7,得到4 7,最后一次合并代价为11,总代价为4+7+11=22;问题是:找出一种合理的方法,使总的代价最小。输出最小代价。

#include <bits/stdc++.h>
using namespace std;
const int  N = 310;
int dp[N][N];
int a[310],sum[310];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
    for(int l=1;l<=n;l++)
        for(int i=1;i+l<=n;i++)
        {
            int j=i+l;
            dp[i][j]=23333333;
            for(int k=i;k<=j;k++)dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
        }
    cout<<dp[1][n];
    return 0;
}

另外就是能量项链 小技巧

zzz

一定要枚举每个区间最后合并的一个

#include<iostream>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
int n,a[500],dp[500][500];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i+n]=a[i];}
    for(int j=2;j<=2*n-1;j++)
        for(int i=j-1;i>0 && j-i<n;i--)
            for(int k=i;k<j;k++)dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+a[i]*a[k+1]*a[j+1]);
    int mx=-1;
    for(int i=1;i<=n;i++)mx=max(dp[i][i+n-1],mx);
    cout<<mx;
    return 0;
}
原文地址:https://www.cnblogs.com/Kong-Ruo/p/7552996.html