标签:北京 size lse nes nbsp icp 数组 else style
题意:
合并石子的升级版。一堆石子,编号为1到n,每堆石子有其权值,一次只能合并连续的石子L到R堆,每次合并的代价为各堆石子的权值,求最后一堆的最小代价,不能完成输出0。
思路:
考虑区间dp做法,因为这个题与堆数有关,dp中加入一维堆数。
dp[i[[j][p]表示石子从i到j合并成p堆的最小花费,状态很重要。
状态转移:
当p>1&&i<=k<j(不表示合并,只表示合并的方案)
dp[i][j][p]=dp[i][k][1]+dp[k+1][j][p-1](表示区间i到j分成p堆的方案枚举,因为p堆总数1堆+p-1堆)
当p==1&&L<=p<=R(表示真正的合并)
dp[i][j][1]=dp[i][j][p]+pre[j]-pre[i-1]。
初始化:
求最小,首先f把需要用的的数组范围内的初始化INF
dp[i][i][1]=0,表示没有合并的自己不需要代价
也存在一些边界条件处理,自己注意一下即可。
代码:
#include <iostream> #include<bits/stdc++.h> using namespace std; const int N=105; int dp[N][N][N];//区间i到j分成k堆的最小代价 const int INF=0x3f3f3f3f; int a[N]; int pre[N]; void init(int n){ for(int i=1;i<=n;i++){ scanf("%d",&a[i]); } for(int i=1;i<=n;i++){ pre[i]=pre[i-1]+a[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]=INF; for(int i=0;i<N;i++) dp[i][i][1]=0; } int main() { int n,l,r; while(~scanf("%d%d%d",&n,&l,&r)){ init(n); for(int len=1;len<=n;len++) for(int i=1;i+len-1<=n;i++){ int j=i+len-1; for(int p=2;p<=len;p++) { for(int k=i;k<j&&j-k>=p-1;k++) { dp[i][j][p]=min(dp[i][j][p],dp[i][k][1]+dp[k+1][j][p-1]); if(p>=l&&p<=r)dp[i][j][1]=min(dp[i][j][1],dp[i][j][p]+pre[j]-pre[i-1]); } } } if(dp[1][n][1]==INF){ printf("0\n"); } else{ printf("%d\n",dp[1][n][1]); } } return 0; }
Pangu and Stones 北京2017ICPC(三维区间DP)
标签:北京 size lse nes nbsp icp 数组 else style
原文地址:https://www.cnblogs.com/gzr2018/p/11438390.html