做了一些區間DP的題目,總結如下
1.Multiplication Puzzle
原題地址:http://poj.org/problem?id=1651
題意:
給定一個序列,可以依次從序列中取走除了左右兩端點之外的元素,每次取走一個元素,獲得該元素乘以它左右兩邊元素乘積的點數,求可能的最小點數
題解:
枚舉區間中最后一個被取走的元素,實現區間的分割,也就是狀態的轉移。
2.Dire Wolf
原題地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=5115
題意:
有一群狼站成一排,每個狼有基礎的攻擊力,同時有一個輔助攻擊力,每個狼的總攻擊力是基礎攻擊力加上相鄰的狼給予的輔助攻擊力之和,求殺狼的次序使得收到的總攻擊力之和最小。
題解:和上一題非常相似

#include<bits/stdc++.h> #define clr(x,y) memset((x),(y),sizeof(x)) using namespace std; typedef long long LL; const int maxn=200; const int inf=1e9; int A[maxn+5]; int B[maxn+5]; int dp[maxn+5][maxn+5]; int n; int DP(int l,int r) { if (dp[l][r]!=-1) return dp[l][r]; if (l==r-1) return dp[l][r]=0; dp[l][r]=inf; for (int k=l+1;k<=r-1;++k) { int tmp=A[k]+B[l]+B[r]; dp[l][r]=min(dp[l][r],DP(l,k)+DP(k,r)+tmp); } return dp[l][r]; } void solve(int C) { A[0]=0; A[n+1]=0; B[0]=0; B[n+1]=0; clr(dp,-1); int ans=DP(0,n+1); printf("Case #%d: %d\n",C,ans); } int main(void) { #ifdef ex freopen ("../in.txt","r",stdin); //freopen ("../out.txt","w",stdout); #endif int T; scanf("%d",&T); for (int Case=1;Case<=T;++Case) { scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d",&A[i]); for (int i=1;i<=n;++i) scanf("%d",&B[i]); solve(Case); } }
3.男神的禮物
原題地址:http://acm.uestc.edu.cn/#/problem/show/1131
題意:略
題解:略

#include<bits/stdc++.h> #define clr(x,y) memset((x),(y),sizeof(x)) using namespace std; typedef long long LL; const int maxn=100; const int inf=1e6; int n; int dp[maxn+5][maxn+5]; int A[maxn+5]; int sum[maxn+5]; void solve() { clr(dp,0); clr(sum,0); for (int i=1;i<=n;++i) sum[i]=(sum[i-1]+A[i])%100; for (int i=n;i>=1;--i) { for (int j=i;j<=n;++j) { dp[i][j]=inf; if (i==j) dp[i][j]=0; for (int k=i;k<=j-1;++k) { int c1=(sum[k]-sum[i-1]+100)%100; int c2=(sum[j]-sum[k]+100)%100; dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+c1*c2); } //printf("%d %d %d\n",i,j,dp[i][j]); } } printf("%d\n",dp[1][n]); } int main(void) { #ifdef ex freopen ("../in.txt","r",stdin); //freopen ("../out.txt","w",stdout); #endif int T; scanf("%d",&T); while (T--) { scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d",&A[i]); solve(); } }
(對於區間DP,循環的寫法相比記憶化要快若干倍,但是也更容易寫錯,包括初始化,邊界條件等都需要注意)
4.You Are the One (難)
原題地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=4283
題意:略
題解:通過枚舉區間左端點的出棧時間實現了區間的分割
5.Coloring Brackets
原題地址:http://www.codeforces.com/contest/149/problem/D
題意:略
題解:略
6.柱爺的戀愛
原題地址:http://acm.uestc.edu.cn/#/problem/show/1321
題意:略
題解:枚舉左端點的配對括號來實現區間的分割。
總結:
區間DP主要涉及兩類問題,區間最優解和區間計數。
區間最優解往往要枚舉區間的分界點,分割區間,子區間的最優解合並之后就是原區間的最優解。
區間計數往往也要分割區間,但是有不遺漏不重復的要求,以上的兩道題都用到了枚舉左端點對應元素的技巧。
區間的分割是區間DP的重要思想