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表示路径,注意:状态转移方程第一二步不可以颠倒
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 f[i][j] = max(f[i - 1][j], f[i][j - 1]); 23 if (a[i] == b[j]) f[i][j] = f[i - 1][j - 1] + 1 ; 24 } 25 cout << f[n][m] << endl; 26 27 string res; 28 // 一个倒序的过程 29 for (int i = n, j = m; i && j; ) 30 { 31 if (a[i] == b[j]) res += a[i], i --, j --; 32 else if (f[i - 1][j] > f[i][j - 1]) i --; 33 else j --; 34 } 35 36 reverse(res.begin(), res.end()); 37 38 cout << res << endl; 39 return 0; 40 }
标签:10,01,int,cin,ACM,DP,序列,include,week7 From: https://www.cnblogs.com/Zac-saodiseng/p/16992948.html