区间dp——1

写在前边

区间dp的简介:区间dp总的来说可以算作是线性dp中的一种,通过由比它更小的几个区间所代表的状态转移而来,因此,区间dp的策略也主要是划分区间的方法。我们可以通过求不同区间的最值进而求得整体宏观的区间最值。

经典例题

合并石子(简单版)

Describtion

1 有N堆石子排成一排(n<=100),现要将石子有次序地合并成一堆,规定每次只能选相邻的两堆合并成一堆,并将新的一堆的石子数,记为改次合并的得分,编一程序,由文件读入堆数n及每堆石子数(<=200);
2 
3 (1)选择一种合并石子的方案,使得做n-1次合并,得分的总和最少
4 
5 (2)选择一种合并石子的方案,使得做n-1次合并,得分的总和最多

 

Analyze

通过读题,我们可以分析,在[l,r] 区间合并之前,一定有l ~ r之间每一堆石子已经被合并,其重量是l~r之间所有石子重量的总和,所以我们可以像Floyd算法那样,在过程量中设一个参数k,k是用来标记过程中的合并的中间量,及有[l~k]和[k + 1 ~ r]一定可以合并成[l ~ r]的区间,k可以叫做转移的决策。

我们设区间长度为len,len可以表示为len = r - l + 1,通过左右端点状态表示dp的状态,我们可以写出此时的状态转移方程F[l,r] = min(max){F[l,k] + F[k + 1,r]} 我们目标求出的是F[1,N].

 1 //函数
 2 memset(f,0x3f,sizeof(f));
 3 for(int i = 1;i <= n;i++)
 4 {
 5     f[i][i] = 0;
 6     sum[i] = sum[i - 1] + a[i];
 7 }
 8 for(int len = 2;len <= n;len++)
 9 {
10     for(int l = 1;l <= n - len + 1;l++)
11     {
12         int r = l + len + 1;
13         for(int k = 1;k < r;k++)
14         {
15             f[l][r] = min(f[l][r],f[l][k] + f[k + 1][r]);
16         }
17         f[l][r] += sum[r] - sum[l - 1];
18     }
19 }

 

完整代码

区间dp——1
 1 #include<algorithm>
 2 #include<iostream>
 3 #include<iomanip>
 4 #include<cstdio>
 5 #include<string.h>
 6 #include<cmath>
 7 #define maxn 101
 8 
 9 using namespace std;
10 
11 int f_1[maxn][maxn];
12 int sum[maxn];
13 int a[maxn];
14 int f_2[maxn][maxn];
15 int k[maxn];
16 
17 int main()
18 {
19     int n;
20     cin >> n;
21     memset(f_1, 0x3f, sizeof(f_1));
22     for (int i = 1; i <= n; i++)
23     {
24         cin >> a[i];
25     }
26     for (int i = 1; i <= n; i++)
27     {
28         f_1[i][i] = 0;
29         sum[i] = sum[i - 1] + a[i];
30     }
31     for (int j = 1; j <= n; j++)
32     {
33         f_2[j][j] = 0;
34         k[j] = k[j - 1] + a[j];
35     }
36     for (int i = 2; i <= n; i++)
37     {
38         for (int j = 1; j <= n - i + 1; j++)
39         {
40             int r = j + i - 1;
41             for (int k = j; k < r; k++)
42             {
43                 f_1[j][r] = min(f_1[j][r], f_1[j][k] + f_1[k + 1][r]);
44                 f_2[j][r] = max(f_2[j][r], f_2[j][k] + f_2[k + 1][r]);
45             }
46             f_1[j][r] += sum[r] - sum[j - 1];
47             f_2[j][r] += k[r] - k[j - 1];
48         }
49     }
50     int ans = 99999999999999;
51     int ans1 = 0;
52     ans = f_1[1][n];
53     ans1 = f_2[1][n];
54     printf("%d\n", ans);
55     printf("%d", ans1);
56     return 0;
57 }
点开以查看

 


the end.

上一篇:力扣【动态规划】-中等题-122买卖股票时期


下一篇:6.7 重复的子字符串