当前位置:   article > 正文

备战蓝桥杯---动态规划(入门1)

备战蓝桥杯---动态规划(入门1)

先补充一下背包问题

于是,我们把每一组当成一个物品,f[k][v]表示前k组花费v的最大值

转移方程还是max(f[k-1][v],f[k-1][v-c[i]]+w[i])

伪代码(注意循环顺序):

for 所有组:

        for v=max.....0

                for i:f[v]=max(f[v],f[v-c[i]]+w[i])

下面看看区间dp的应用:

下面是分析:

我们令f[i][j]表示从ai到aj的串中,有多少个匹配的括号。

我们分析最左边的,1.它匹配:f[i][j]=max(f[i][k]+f[k+1][j]),对于最后一个,若可以匹配+2,不可以就不加。

2.他不匹配:f[i][j]=max(f[i+1][j]);

下面是AC代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int dp[105][105];
  4. string s;
  5. int f(int i,int j){
  6. if(i>=j) return dp[i][j]=0;
  7. if(dp[i][j]!=-1) return dp[i][j];
  8. for(int k=i+1;k<=j-1;k++){
  9. if((s[i]=='('&&s[k]==')')||(s[i]=='['&&s[k]==']')) dp[i][j]=max(dp[i][j],f(i+1,k-1)+f(k+1,j)+2);
  10. else dp[i][j]=max(dp[i][j],f(i+1,k-1)+f(k+1,j));
  11. }
  12. dp[i][j]=max(dp[i][j],f(i+1,j));
  13. if((s[i]=='('&&s[j]==')')||(s[i]=='['&&s[j]==']')){
  14. dp[i][j]=max(dp[i][j],f(i+1,j-1)+2);
  15. }
  16. else dp[i][j]=max(dp[i][j],f(i+1,j-1));
  17. return dp[i][j];
  18. }
  19. int main(){
  20. while(cin>>s){
  21. if(s=="end") break;
  22. memset(dp,-1,sizeof(dp));
  23. cout<<f(0,s.size()-1)<<endl;
  24. }
  25. }

接题:

法1,我们倒序求一串,相当于求他们的公共子序列。

法2.区间dp,f[i][j]表示ai,aj的最长回文子序列。

ai==aj f[i][j]=f[i+1][j-1]+2;

否则,f[i][j]=max(f[i+1][j],f[i][j-1])

下面是AC代码:

  1. class Solution {
  2. public:
  3. int longestPalindromeSubseq(string s) {
  4. int a[1050][1050];
  5. int n=s.length();
  6. for(int j=0;j<=n-1;j++){
  7. a[j][j]=1;
  8. }
  9. for(int j=1;j<=n-1;j++){
  10. for(int i=j-1;i>=0;i--){
  11. if(s[i]==s[j]) a[i][j]=a[i+1][j-1]+2;
  12. else a[i][j]=max(a[i+1][j],a[i][j-1]);
  13. }
  14. }
  15. return a[0][n-1];
  16. }
  17. };

我们再思考一下:如果是要求连续的?

我们用bool数组f[i][j]表示i---j是否为回文

转移方程:if a[i]==a[j]&&f[i+1][j-1]==1回文,反之不回文

下面看一个具体应用:

我们先不考虑它成环,我们令dp[i][j]为i---j的合并的max,那么我们枚举最后一次合并的分界+i---j的和即可,转移方程为dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1])

我们再考虑成环,其实只是断开点的不同,换句话说,1234的情况变成了1234,2341,3412,4123,我们只要取max即可,为方便同时利用上一次的记入,我们直接for12341234即可。

下面是AC代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,dp[402][402],dp1[402][402],a[402],sum[402];
  4. int f(int i,int j){
  5. if(i==j) return dp[i][j]=0;
  6. if(dp[i][j]!=-1) return dp[i][j];
  7. for(int k=i;k<=j-1;k++){
  8. dp[i][j]=max(dp[i][j],f(i,k)+f(k+1,j)+sum[j]-sum[i-1]);
  9. }
  10. return dp[i][j];
  11. }
  12. int f1(int i,int j){
  13. if(i==j) return dp1[i][j]=0;
  14. if(dp1[i][j]!=-1) return dp1[i][j];
  15. dp1[i][j]=f(i+1,j)+sum[j]-sum[i-1];
  16. for(int k=i;k<=j-1;k++){
  17. dp1[i][j]=min(dp1[i][j],f1(i,k)+f1(k+1,j)+sum[j]-sum[i-1]);
  18. }
  19. return dp1[i][j];
  20. }
  21. int main(){
  22. cin>>n;
  23. for(int i=1;i<=n;i++){
  24. scanf("%d",&a[i]);
  25. sum[i]=sum[i-1]+a[i];
  26. }
  27. for(int i=n+1;i<=2*n;i++){
  28. a[i]=a[i-n];
  29. sum[i]=sum[i-1]+a[i];
  30. }
  31. memset(dp,-1,sizeof(dp));
  32. memset(dp1,-1,sizeof(dp1));
  33. int ans1=0,ans2=f1(1,n);
  34. for(int i=1;i<=n;i++){
  35. ans2=min(ans2,f1(i,i+n-1));
  36. }
  37. cout<<ans2<<endl;
  38. for(int i=1;i<=n;i++){
  39. ans1=max(ans1,f(i,i+n-1));
  40. }
  41. cout<<ans1<<endl;
  42. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/104138
推荐阅读
相关标签
  

闽ICP备14008679号