线性dp

一:数字三角形

给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

        7
      3   8
    8   1   0
  2   7   4   4
4   5   2   6   5

输入格式

第一行包含整数n,表示数字三角形的层数。

接下来n行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。

输出格式

输出一个整数,表示最大的路径数字和。

数据范围

1n5001≤n≤500,
1000010000−10000≤三角形中的整数≤10000

输入样例:

5
7
3 8
8 1 0 
2 7 4 4
4 5 2 6 5

输出样例:

30


 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 510;
 5 const int INF = 0x3f3f3f3;
 6 
 7 int map[N][N], dp[N][N];
 8 int n;
 9 
10 int main(){
11     cin >> n;    
12     for(int i = 1;i <= n;++i) 
13         for(int j = 1;j <= i;++j)
14             cin >> map[i][j];
15     
16     for(int i = 0;i <= n;++i)
17         for(int j = 0;j <= i+1;++j)
18             dp[i][j] = -INF;
19     
20     dp[1][1] = map[1][1];
21     for(int i = 2;i <= n;++i)
22         for(int j = 1;j <= i;++j)
23             dp[i][j] = max(dp[i-1][j-1]+map[i][j], dp[i-1][j]+map[i][j]); 
24     
25     int res = 0;
26     for(int i = 1;i <= n;++i) res = max(res, dp[n][i]);
27     cout << res << endl;
28     return 0;
29 }
View Code

二:最长上升子序列

给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。

输入格式

第一行包含整数N。

第二行包含N个整数,表示完整序列。

输出格式

输出一个整数,表示最大长度。

数据范围

1N10001≤N≤1000,
109109−109≤数列中的数≤109

输入样例:

7
3 1 2 1 8 5 6

输出样例:

4

 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 1000;
 5 int arr[N];
 6 int dp[N];
 7 
 8 int main(){
 9     int n; cin >> n;
10     for(int i = 0;i < n;++i) cin >> arr[i];
11     
12     for(int i = 0;i < n;++i){
13         dp[i] = 1;
14         for(int j = 0;j < i;++j)
15             if(arr[j] < arr[i])
16                 dp[i] = max(dp[i], dp[j]+1);
17     }
18     int res = 0;
19     for(int i = 0;i < n;++i) res = max(res, dp[i]);
20     cout << res << endl;
21     return 0;
22 }
View Code

三:最长公共子序列

给定两个长度分别为N和M的字符串A和B,求既是A的子序列又是B的子序列的字符串长度最长是多少。

输入格式

第一行包含两个整数N和M。

第二行包含一个长度为N的字符串,表示字符串A。

第三行包含一个长度为M的字符串,表示字符串B。

字符串均由小写字母构成。

输出格式

输出一个整数,表示最大长度。

数据范围

1N10001≤N≤1000,

输入样例:

4 5
acbd
abedc

输出样例:

3


 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 char a[N], b[N];
 7 int dp[N][N];
 8 
 9 int main(){
10     int n, m;cin >> n >> m;
11     cin >> a+1;cin >> b+1;
12     for(int i = 1;i <= n;++i)   
13         for(int j = 1;j <= m;++j)
14             if(a[i] == b[j])
15                 dp[i][j] = dp[i-1][j-1] + 1;
16             else 
17                 dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
18     
19     cout << dp[n][m] << endl;
20     return 0;
21 }
View Code

四:最短编辑距离

给定两个字符串A和B,现在要将A经过若干操作变为B,可进行的操作有:

  1. 删除–将字符串A中的某个字符删除。
  2. 插入–在字符串A的某个位置插入某个字符。
  3. 替换–将字符串A中的某个字符替换为另一个字符。

现在请你求出,将A变为B至少需要进行多少次操作。

输入格式

第一行包含整数n,表示字符串A的长度。

第二行包含一个长度为n的字符串A。

第三行包含整数m,表示字符串B的长度。

第四行包含一个长度为m的字符串B。

字符串中均只包含大写字母。

输出格式

输出一个整数,表示最少操作次数。

数据范围

1n,m10001≤n,m≤1000

输入样例:

10 
AGTCTGACGC
11 
AGTAAGTAGGC

输出样例:

4

 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 char a[N], b[N];
 7 int dp[N][N]; //表示从1到i 和 1到j 匹配的最小操作次数
 8 
 9 int main(){
10     int n = 0;cin >> n;
11     cin >> a+1;
12     int m = 0;cin >> m;
13     cin >> b+1;
14     
15     for(int i = 0;i <= m;++i) dp[0][i] = i;
16     for(int i = 0;i <= n;++i) dp[i][0] = i;
17     
18     for(int i = 1;i <= n;++i)
19         for(int j = 1;j <= m;++j){
20             dp[i][j] = min(dp[i][j-1] + 1, dp[i-1][j] + 1);//插入和替换
21             if(a[i] == b[j])
22                 dp[i][j] = min(dp[i][j], dp[i-1][j-1]);
23             else 
24                 dp[i][j] = min(dp[i][j], dp[i-1][j-1] + 1);
25         }
26     
27     cout << dp[n][m] << endl;
28     return 0;
29 }
View Code
原文地址:https://www.cnblogs.com/sxq-study/p/12303589.html