ACM预备队-week7(DP1)
1.[NOIP2005 普及组] 采药
题目链接:P1048 [NOIP2005 普及组] 采药 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
01背包,可以利用滚动数组优化为一维。
1 #include <bits/stdc++.h>
2 using namespace std;
3 const int N=1010;
4 int f[N];
5 int main()
6 {
7 int T,M;
8 cin>>T>>M;
9 for(int i=1;i<=M;i++)
10 {
11 int v,w;
12 cin>>v>>w;
13 for(int j=T;j>=v;j--)
14 {
15 f[j]=max(f[j],f[j-v]+w);
16 }
17 }
18 cout<<f[T];
19 return 0;
20 }
2.最长上升子序列
题目链接:B3637 最长上升子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
如果数据范围是1e4数量级以上,就不能用朴素算法了,O(N2)的复杂度
1 #include <bits/stdc++.h>
2 using namespace std;
3 const int N=5010;
4 int a[N],f[N];
5 int n;
6 int main()
7 {
8 cin>>n;
9 for(int i=1;i<=n;i++)cin>>a[i];
10 for(int i=1;i<=n;i++)
11 {
12 f[i]=1;
13 for(int j=1;j<i;j++)
14 if(a[j]<a[i])
15 {
16 f[i]=max(f[i],f[j]+1);
17 }
18 }
19 int ans=0;
20 for(int i=1;i<=n;i++)ans=max(ans,f[i]);
21 cout<<ans;
22 return 0;
23 }
3.最大子段和:
题目链接:P1115 最大子段和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
该算法更为简便之处是忽略了对子序列的寻找比较,而是根据规律直接找出最佳答案.
对于含有正数的序列而言,最大子序列肯定是正数,所以头尾肯定都是正数.我们可以从第一个正数开始算起,每往后加一个数便更新一次和的最大值;当当前和成为负数时,则表明此前序列无法为后面提供最大
子序列和,因此必须重新确定序列首项.
首先定义一个答案,必须在数据最小值范围之外,定义S是扫描到第i个数时,前 i-1 个数的最大子段和,将子段与0比较即可,反正是玄学。。。
1 #include <bits/stdc++.h>
2 using namespace std;
3 const int N=2e5+10;
4 int a[N];
5 int main()
6 {
7 int res=-1e9,n,s=0;
8 cin>>n;
9 for(int i=0;i<n;i++)cin>>a[i];
10 for(int i=0;i<n;i++)
11 {
12 if(s<=0)s=0;
13 s+=a[i];
14 res=max(res,s);
15 }
16 cout<<res;
17 return 0;
18
19 }
4.最长公共子序列(LCS)
题目链接:LCS - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)


其中00表示不含i和j,01表示不含i但含j(这个j可能选也可能不选),10表示含i但不含j(这个i可能选也可能不选),11表示含i含j,但是,11有一个前提,就得是当a[i]==b[j]时。
00:f[i-1,j-1] 01:f[i-1,j] 10:f[i,j-1] 11:if(a[i]==b[j])f[i-1][j-1]+1
但是因为00其实就是01和10的子集,所以可以不写00,此时01和10其实不是真正意义的选与不选,但是最大值只要包括了而且没有越界,就算情况重复也不影响max值
因为此题还要输出路径,所以还得倒着来一遍。用res表示路径。
状态方程解释很清晰链接:最长公共子序列 - 动态规划 Longest Common Subsequence - Dynamic Programming_哔哩哔哩_bilibili
1 #include <iostream>
2 #include <algorithm>
3 #include <cstring>
4
5
6 using namespace std;
7
8 const int N = 1010;
9
10 int n, m;
11 char a[N], b[N];
12 int f[N][N];
13
14 int main()
15 {
16 cin >> n >> m;
17 cin >> a + 1 >> b + 1;
18
19 for (int i = 1; i <= n; i ++)
20 for (int j = 1; j <= m; j ++)
21 {
22 if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1 ;
23 else f[i][j] = max(f[i - 1][j], f[i][j - 1]);
24
25 }
26 cout << f[n][m] << endl;
27
28 string res;
29 // 一个倒序的过程
30 for (int i = n, j = m; i && j; )
31 {
32 if (a[i] == b[j]) res += a[i], i --, j --;
33 else if (f[i - 1][j] > f[i][j - 1]) i --;
34 else j --;
35 }
36
37 reverse(res.begin(), res.end());
38
39 cout << res << endl;
40 return 0;
41 }

浙公网安备 33010602011771号