CometOJ 双倍快乐(简单DP)

Posted doublebit

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CometOJ 双倍快乐(简单DP)相关的知识,希望对你有一定的参考价值。

链接:https://www.cometoj.com/contest/48/problem/B

题意:给出一串数列,要求在这个数列中找出两条“不相交”的非下降子序列使得子序列之和最大。“不相交”即不存在任意的ai同时存在于两个子序列中。

分析:笔者刷题量不多,这道题对笔者加深动态规划求子序列的理解很有帮助;题目要求非下降子序列的最大和,这里我们要求的是两条子序列。做题时的第一想法是走两遍DP,先求出一条和最大的子序列,把这条子序列中的元素给剔除,接着再重复该步骤,得到另一条和最大的子序列,最后把两条子序列的和加起来。但是,这种做法是存在后效性的,我们的目的是要求得两条子序列的和最大,如果每次只是单纯的找和最大的子序列,那么很有可能在第一次选元素时就断了使得子序列总和最大的“桥梁”。好比方说:5 4 4 5 4;通过该方案得到的两条序列会是:“4 4 5”、“5”,最终结果是18。但最优的方案其实是:“4 4 4”、“5 5”,结果为22。

  设dp[i][j]为两条子序列的末端分别为i和j时的子序列和,dp[0][0] = 0;其状态转移方程可以由单个子序列的转移方程推广得到,详见代码部分。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main() 
 6     int n;
 7     scanf("%d",&n);
 8 
 9     int num[n+1];
10     num[0] = 0;
11     for (int i=1;i<=n;i++) 
12         scanf("%d",&num[i]);
13     
14 
15     int dp[n+1][n+1];
16     memset(dp,0,sizeof(dp));
17     int ans = 0;
18     for (int i=1;i<=n;i++) 
19         for (int j=0;j<i;j++) 
20             if (num[i] >= num[j]) 
21                 for (int k=0;k<i;k++) 
22                     dp[i][k] = max(dp[i][k],dp[j][k] + num[i]);
23                     dp[k][i] = max(dp[k][i],dp[k][j] + num[i]);
24                     ans = max(ans,max(dp[i][k],dp[k][i]));
25                 
26             
27         
28     
29     printf("%d\n",ans);
30     return 0;
31 

 

以上是关于CometOJ 双倍快乐(简单DP)的主要内容,如果未能解决你的问题,请参考以下文章

树形dp①

cometoj---contest#3 棋盘

符文能量(Comet OJ - Contest #8)

肥宅快乐树 换根+树形DP/dfs

20190809 B组总结

第三讲 数学与简单DP完结