區間類動態規劃是線性動態規劃的擴展,它在分階段地劃分問題時,與階段中元素出現的順序和由前一階段的哪些元素合併而來由很大的關係。令狀態表示將下標位置到的所有元素合併能獲得的價值的最大值,那麼,其中爲將這兩組元素合併起來的代價1,。
例題一 石子合併
例題:luogu1880 [NOI1995]石子合併
思路參考自:https://oi-wiki.org/dp/interval/。簡單來說,三重for循環,第一重是長度,第二重是開始下標(前兩重可以確定結束下標),第三重是合併位置。
解決環的問題:複製一份,變成的序列。
注意點:最小值初始化表示一個石頭不需要代價,其他點(無窮大)。
hyy提供的代碼:
#include <bits/stdc++.h>
using namespace std;
int f[210][210];
int f1[210][210];
int n;
int a[210];
int sum[210];
int main(){
cin >> n;
for(int i=1;i<=n;i++){
cin >> a[i];
a[i+n]=a[i];
}
for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i];
for(int i=1;i<=2*n;i++){
for(int j=1;j<=2*n;j++){
f1[i][j]=2e6;
}
}
for(int i=1;i<=2*n;i++) f1[i][i]=0,f[i][i]=0;
for(int len=2;len<=n;len++){
for(int i=1;i<=2*n;i++){
int j=i+len-1;
if(j>=2*n) break;
for(int k=i;k<j;k++){
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
f1[i][j]=min(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]);
}
}
}
int ans=0,ans1=2e6;
for(int i=1;i<=n;i++){
ans1=min(ans1,f1[i][i+n-1]);
ans=max(ans,f[i][i+n-1]);
}
cout << ans1<<endl<<ans;
return 0;
}
例題二 能量項鍊
處理方式與例題一非常類似,唯一要修改的地方是:的cost爲.
代碼:
/* ***********************************************
Author : VFVrPQ
Created Time : 一 3/ 2 14:45:08 2020
File Name : luogu1063能量項鍊.cpp
Problem :
Description :
Solution :
Tag :
************************************************ */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <iomanip>
using namespace std;
#define DEBUG(x) cout<<x<<endl;
const int N = 2e2+10;
const int M = 1e9+7;
const int INF = 1e9+7;
int dp[N][N];
int a[N];
int n;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[n+i] = a[i];
}
for (int i=1;i<=n+n;i++) dp[i][i] = 0;
for (int len=2;len<=n;len++){
for (int i=1;i<=n+n;i++){
int j = i+len-1;
if (j>=n+n) break;
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 ans = 0;
for (int i=1;i<=n;i++) ans = max(ans, dp[i][i+n-1]);
printf("%d\n",ans);
return 0;
}