Comet OJ - Contest #6 解題報告

傳送門:https://www.cometoj.com/contest/48c++


B:雙倍快樂(簡單DP)spa

題意:給出一串數列,要求在這個數列中找出兩條「不相交」的非降低子序列使得子序列之和最大。「不相交」即不存在任意的ai同時存在於兩個子序列中。code

分析:筆者刷題量很少,這道題對筆者加深動態規劃求子序列的理解頗有幫助;題目要求非降低子序列的最大和,這裏咱們要求的是兩條子序列。作題時的第一想法是走兩遍DP,先求出一條和最大的子序列,把這條子序列中的元素給剔除,接着再重複該步驟,獲得另外一條和最大的子序列,最後把兩條子序列的和加起來。可是,這種作法是存在後效性的,咱們的目的是要求得兩條子序列的和最大,若是每次只是單純的找和最大的子序列,那麼頗有可能在第一次選元素時就斷了使得子序列總和最大的「橋樑」。比如方說:5 4 4 5 4;經過該方案獲得的兩條序列會是:「4 4 5」、「5」,最終結果是18。但最優的方案實際上是:「4 4 4」、「5 5」,結果爲22。blog

  設dp[i][j]爲兩條子序列的末端分別爲i和j時的子序列和,dp[0][0] = 0;其狀態轉移方程能夠由單個子序列的轉移方程推廣獲得,詳見代碼部分。get

 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 }
相關文章
相關標籤/搜索