线性dp

1.数字三角形。acwing 898.

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 520,INF = 1e9;
 5 int n;
 6 int a[N][N]; //表示每一个点
 7 int f[N][N]; //表示状态
 8 
 9 int main()
10 {
11     cin >> n;
12     for (int i = 1; i <= n; i ++ )
13        for (int j = 1; j <= i; j ++ )
14            cin >> a[i][j];
15     
16     for (int i = 0; i <= n; i ++ )
17        for (int j = 0; j <= i + 1; j ++ ) //每行多初始化一个,表示三角形最右边的右上角表示负无穷
18           f[i][j] = -INF; //避免处理边界情况,先将状态初始化为负无穷
19     
20     f[1][1] = a[1][1];
21     
22     for (int i = 2; i <= n; i ++ )
23        for (int j = 1; j <= i; j ++ )
24        f[i][j] = max(f[i - 1][j - 1] + a[i][j],f[i - 1][j] + a[i][j]);
25     
26     int res = -INF;   
27     for (int i = 1; i <= n; i ++ ) //枚举三角形底边终点的状态的最大值
28        res = max(res,f[n][i]);
29        
30     cout << res << endl;
31            
32     return 0;
33 }
View Code
复制代码

 2.最长上升子序列

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 int n;
 7 int a[N],f[N];
 8 
 9 int main ()
10 {
11     scanf("%d", &n);
12     for (int i = 1; i <= n; i ++ ) cin >> a[i];
13     
14     for (int i = 1; i <= n; i ++ )//从前往后计算每一个状态
15     {
16         f[i] = 1;//表示以i结尾的子序列的长度为1 只有a[i]这一个数
17         for (int j = 1; j < i; j ++ )
18           if(a[j] < a[i]) f[i] = max(f[i],f[j] + 1);
19     }
20     
21     int res = 0;
22     for (int i = 1; i <= n; i ++ ) res = max(res,f[i]); //枚举所有中点;
23     
24     cout << res << endl;
25     
26     return 0;
27 }
View Code
复制代码

 

3.最长公共子序列

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n,m;
 5 const int N = 1010;
 6 char a[N],b[N];
 7 int f[N][N]; //状态表示为第一个字符串的前i个和第二个字符串的前j个构成的公共子序列
 8 
 9 int main()
10 {
11     scanf("%d %d", &n, &m);
12     
13     for (int i = 1; i <= n; i ++ ) cin >> a[i];
14     for (int i = 1; i <= m; i ++ ) cin >> b[i];
15     
16     for (int i = 1; i <= n; i ++ ) 
17        for (int j = 1; j <= m; j ++ )
18        {
19            f[i][j] = max(f[i - 1][j],f[i][j - 1]); //01和10状态包含了00状态
20            //01和10分别表示a字符串的最后一个不选以及b的最后一个选
21            if(a[i] == b[j]) f[i][j] = max(f[i][j],f[i - 1][j - 1] + 1);
22        }
23     
24     cout << f[n][m] << endl;
25 }
View Code
复制代码

 精简版:二分优化

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 100010;
 5 
 6 int n;
 7 int a[N]; //表示数组
 8 int q[N]; //表示所有不同长度的上升子序列的结尾的最小值
 9 
10 int main ()
11 {
12     scanf("%d", &n);
13     for (int i = 0; i < n; i ++ ) cin >> a[i];
14     
15     int len = 0;
16     q[0] = -2e9;
17     
18     for (int i = 0; i < n; i ++ )
19     {
20         int l = 0,r = len;
21         while(l < r)
22         {
23             int mid = l + r  + 1 >> 1;
24             if(q[mid] < a[i]) l = mid;
25             else r = mid - 1;
26         }
27         len = max(len,r + 1);
28         q[r + 1] = a[i];
29     }
30     
31     cout << len << endl;
32     return 0;
33 }
View Code
复制代码

 4.最短编辑距离

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 int n,m;
 7 char a[N],b[N];
 8 int f[N][N]; //集合表示 由a[1 ~ i]变成b[1 ~ j]的操作方式
 9 
10 int main()
11 {
12     scanf("%d%s", &n,a + 1);
13 
14     scanf("%d%s", &m,b + 1);
15     
16     for (int i = 0; i <= m; i ++ ) f[0][i] = i;//b的前i个字母和a的前0个字母匹配,只能将a的前i个字母增加i次
17     for (int i = 0; i <= n; i ++ ) f[i][0] = i;//a的前i个字母和b的前零个字母匹配,只能将a个i个字母删除i次
18     
19     for (int i = 1; i <= n; i ++ )
20        for (int j = 1; j <= m; j ++ )
21        {
22            f[i][j] = min(f[i - 1][j] + 1,f[i][j - 1] + 1);//a字符的删和增的操作
23            if(a[i] == b[j]) f[i][j] = min(f[i][j],f[i - 1][j - 1]); //a字符的修改的操作
24            else f[i][j] = min(f[i][j],f[i - 1][j - 1] + 1);
25        }
26        
27     cout << f[n][m] << endl;//把a的前n个字母变成b的前m个字母
28     
29     return 0;
30 }
View Code
复制代码

 5.编辑距离

复制代码
 1 #include <algorithm>
 2 #include <cstring>
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 const int N = 15, M = 1e3 + 10;
 8 
 9 int n, m;
10 char str[M][N];
11 int dp[N][N];
12 
13 int edit_distance(char a[], char b[])
14 {
15     int la = strlen(a + 1), lb = strlen(b + 1);
16     for (int i = 0; i <= lb; i++) {
17         dp[0][i] = i;
18     }
19     for (int i = 0; i <= la; i++) {
20         dp[i][0] = i;
21     }
22     for (int i = 1; i <= la; i++) {
23         for (int j = 1; j <= lb; j++) {
24             dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
25             dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + (a[i] != b[j]));
26         }
27     }
28     return dp[la][lb];
29 }
30 
31 int main()
32 {
33     cin >> n >> m;
34     for (int i = 0; i < n; i++) {
35         cin >> (str[i] + 1);
36     }
37 
38     while (m -- ) {
39         int res = 0;
40         char s[N];
41         int limit;
42         cin >> (s + 1) >> limit;
43         for (int i = 0; i < n; i ++) {
44             if (edit_distance(str[i], s) <= limit) {
45                 res++;
46             }
47         }
48         cout << res << endl;
49     }
50 
51     return 0;
52 }
View Code
复制代码

 

6.整数划分

 

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n;
 5 const int N = 1010,mod = 1e9 + 7;
 6 int f[N];
 7 
 8 //可视为完全背包问题去解决
 9 int main()
10 {
11     scanf("%d", &n);
12     
13     f[0] = 1;
14     
15     for (int i = 1; i <= n; i ++ )
16        for (int j = i; j <= n; j ++ )
17          f[j] = (f[j] + f[j - i]) % mod;
18          
19     cout << f[n] << endl;     
20     
21 }
View Code
复制代码

 第二种方式

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n;
 5 const int N = 1010,mod = 1e9 + 7;
 6 int f[N][N]; //表示所有总和是i,并且恰好表示成J个数的方案
 7 
 8 int main()
 9 {
10     scanf("%d", &n);
11     
12     f[0][0] = 1;
13     
14     for (int i = 1; i <= n; i ++ )
15        for (int j = 1; j <= i; j ++ )
16          f[i][j] = (f[i - 1][j - 1] + f[i - j][j]) % mod;
17     
18     int res = 0;     
19     for (int i = 1; i <= n; i ++ ) res = (res + f[n][i]) % mod; 
20     
21     cout << res << endl;    
22     return 0;
23     
24 }
View Code
复制代码

 

posted @   rw156  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示