区间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; }