區間DP模板題
阿新 • • 發佈:2018-11-12
通用模板
//mst(dp,0) 初始化DP陣列
for(int i=1;i<=n;i++)
{
dp[i][i]=初始值
}
for(int len=2;len<=n;len++) //區間長度
for(int i=1;i<=n;i++) //列舉起點
{
int j=i+len-1; //區間終點
if(j>n) break; //越界結束
for(int k=i;k<j;k++) //列舉分割點,構造狀態轉移方程
{
dp[i][j]=max(dp[ i][j],dp[i][k]+dp[k+1][j]+w[i][j]);
}
}
石子合併(一)
http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=737
石子合併(一)
時間限制:1000 ms | 記憶體限制:65535 KB
難度:3
描述
有N堆石子排成一排,每堆石子有一定的數量。現要將N堆石子併成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過N-1次合併後成為一堆。求出總的代價最小值。
輸入
有多組測試資料,輸入到檔案結束。
每組測試資料第一行有一個整數n,表示有n堆石子。
接下來的一行有n(0< n <200)個數,分別表示這n堆石子的數目,用空格隔開
輸出
輸出總代價的最小值,佔單獨的一行
樣例輸入
3
1 2 3
7
13 7 8 16 21 4 18
樣例輸出
9
239
#include<bits/stdc++.h>
using namespace std;
const int maxn=500;
int dp[maxn][maxn],sum[maxn],x;
int main(){
int n;
while(scanf("%d",&n)!=EOF)
{
memset(dp,0x3f,sizeof(dp));
memset (sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
sum[i]=sum[i-1]+x;
dp[i][i]=0;
}
for(int len=2;len<=n;len++)
{
for(int i=1;i<=n;i++)
{
int j=i+len-1;
if(j>n) break;
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]);
}
}
}
printf("%d\n",dp[1][n]);
}
return 0;
}
平行四邊形優化DP
一般來說,代價值如w[i][j]可以表示為sum[j]-sum[i-1]時就可以用,也就是說代價值可以用字首和表示出來。
用s[i][j]表示區間[i,j]中的最優分割點,那麼第三重迴圈可以從[i,j-1)優化到【s[i][j-1],s[i+1][j]】。(這個時候小區間s[i][j-1]和s[i+1][j]的值已經求出來了,然後通過這個迴圈又可以得到s[i][j]的值)。
#include<bits/stdc++.h>
using namespace std;
const int maxn=500;
int dp[maxn][maxn],sum[maxn],x,s[maxn][maxn];
int main(){
int n;
while(scanf("%d",&n)!=EOF)
{
memset(dp,0x3f,sizeof(dp));
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
sum[i]=sum[i-1]+x;
dp[i][i]=0;
s[i][i]=i;
}
for(int len=2;len<=n;len++)
{
for(int i=1;i<=n;i++)
{
int j=i+len-1;
if(j>n) break;
for(int k=s[i][j-1];k<=s[i+1][j];k++)
{
if(dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]<dp[i][j]){
dp[i][j]=dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1];
s[i][j]=k;
}
}
}
}
printf("%d\n",dp[1][n]);
}
return 0;
}