區間dp入門


 

所謂區間dp,顧名思義就是在一段區間上的動態規划。它既要滿足dp問題的最優子結構和無后效性外,還應該符合在區間上操作的特點。我的理解是往往會對區間進行合並操作。抑或是單個元素(可看成一個小區間)跨區間進行操作。例如括號匹配問題,石子合並問題(通過多次的相鄰合並,最后實質上會產生跨區間的合並,如果你把其中的石子看作參考系的話就很容易感覺出來),還有在整數中插入運算符號的問題(利用運算符的優先級以及交換律可看出)

這樣以來,如果我們要得知一個大區間的情況,由於它必定是由從多個長度不一的小區間轉移而來(轉移情況未知),我們可以通過求得多個小區間的情況,從而合並信息,得到大區間。

對於一個長度為n的區間,確定它的子區間需要首尾兩個指針,顯然子區間數量級為n2,那區間dp的復雜度也就為n2

操作的模板

1     for (int len = 1; len < n; len++) { //操作區間的長度
2         for (int i = 0, j = len; j <= n; i++, j++) { //始末
3             //檢查是否匹配(非必須)
4             for (int s = i; s < j; s++) {
5                 //update
6             }
7         }
8     }
View Code

 

石子合並問題

 1 #include <cstdio>
 2 #define min(x, y) (x > y ? y : x)
 3 #define INF 0x3f3f3f3f
 4 using namespace std;
 5 
 6 const int maxn = 210;
 7 int dp[maxn][maxn];
 8 int sum[maxn];
 9 int a[maxn];
10 
11 int main(int argc, const char * argv[]) {
12     
13     int n;
14     while (~scanf("%d", &n)) {
15         for (int i = 1; i <= n; i++) {
16             scanf("%d", &a[i]);
17             sum[i] = sum[i - 1] + a[i];
18         }
19         for (int len = 1; len < n; len++) { //操作區間的長度
20             for (int i = 1, j = len + 1; j <= n; i++, j++) { //始末
21                 //檢查是否匹配(非必須)
22                 dp[i][j] = INF;
23                 for (int s = i; s < j; s++) {
24                     dp[i][j] = min(dp[i][j], dp[i][s] + dp[s + 1][j] + sum[j] - sum[i - 1]);
25                 }
26             }
27         }
28         printf("%d\n", dp[1][n]);
29     }
30     return 0;
31 }
View Code

 

括號匹配

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 const int maxn = 105;
 7 char str[maxn];
 8 int dp[maxn][maxn];
 9 
10 bool ck(int i, int j) {
11     if ((str[i] == '(' && str[j] == ')') || (str[i] == '[' && str[j] == ']')) {
12         return true;
13     } else {
14         return false;
15     }
16 }
17 
18 int main(int argc, const char * argv[]) {
19     while (~scanf("%s", str)) {
20         if (str[0] == 'e') break;
21         
22         int len;
23         len = strlen(str);
24         memset(dp, 0, sizeof(dp));
25         for (int l = 1; l < len; l++) {  //len =  j - i 為當前區間長度
26             for (int i = 0, j = l; j < len; i++, j++) { // i++, j++
27                 if (ck(i, j)) { // 匹配
28                     dp[i][j] = dp[i + 1][j - 1] + 2;
29                 }
30                 // 討論區間合並情況,求最大值
31                 for (int pos = i; pos < j; pos++) {
32                     dp[i][j] = max(dp[i][j], dp[i][pos] + dp[pos + 1][j]);
33                 }
34             }
35         }
36         printf("%d\n", dp[0][len - 1]);
37         
38     }
39     return 0;
40 }
View Code

 

整數划分

 

 

四邊形不等式優化優化以后再學

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM