zoukankan      html  css  js  c++  java
  • (DP)最大价值事件序列选取

    题目:

    有 T (小于10000)件事情,每件事件有一个开始时间(从1开始)一个结束时间(小于 10000),和一个正整数价值 。 

    求做这些事件所能得到的最大的价值 。

    思考:

    将事件由事件开始先后顺序排序,先开始的排在前面,后开始的排在后面。按这个顺序事件号记录在一个数组order中。

    初始化数组 dp 为 0 , dp[w] 表示 选取了 结束时间为 w 的某事件后 所做事件的总价值。

    初始化变量dpmax = 0 记录dp值的最大值。

    设 end 为 第 i 件 事结束的时间。

    做第 i 件事时,搜索前面做过的 i - 1 件事,找到dp值最大的。设 seek 为 搜索到的dp值最大的事件序号。加上 第 i 件事的价值,转移状态到 dp[end]= max( dp[end] , dp[seek]+ Val[i])

    TIP:由于dp[i] 表示的并不是 1 - i 时间内最大的价值。所以从i - 1处转移并不可靠。而记录的dpmax是全局最大,也就是说,比 事件 i 先开始的事件,不一定结束时间比 事件 i 早。因此也不能单纯的使用 dpmax。只能向前搜索。搜索一个以前做过的事件,且 dp[该事件] 值是最大,继续转移。

    代码:

     1 //
     2 // T 个事件,给出开始时间 结束时间 价值 。 求做这些事件所能获得的最大的价值 。
     3 // O(n^2) 算法 
     4 //
     5 #include <iostream>
     6 #include <stdio.h>
     7 #include <string.h>
     8 #include <algorithm>
     9 
    10 #define MAX 10010
    11 using namespace std;
    12 int B[MAX]; // 事件的开始时间。
    13 int E[MAX]; // 时间的结束时间。
    14 int V[MAX]; // 事件的价值。
    15 int order[MAX]; // 按照起始时间排序所获得的做事件的顺序。
    16 int dp[MAX]; // 做事做到某个时间点所能获得的最大价值。
    17 int dpmax; // 记录当前dp数组中最大的价值。
    18 ////////////////////////////////
    19 ///////////////////////////////
    20 void init()
    21 {
    22     memset(dp , 0 ,MAX * sizeof(int));
    23     dpmax = 0;
    24     return ;
    25 }
    26 bool CMP(int a , int b)
    27 {
    28     if(B[a] > B[b]) return 0;
    29     return 1;
    30 }
    31 int main()
    32 {
    33     int T;
    34     while(~scanf("%d",&T))
    35     {
    36         init();
    37         for(int i = 0 ; i < T ; i++) 
    38         {
    39             cin >> B[i] >> E[i] >> V[i];
    40             order[i] = i;
    41         }
    42         sort(order , order + T , CMP);
    43         //////////////////////////////////////////
    44         for(int i = 0 ; i < T ; i++)
    45         {
    46             int seek = 0;
    47             int begin = B[i];
    48             int end = E[i];
    49             int val = V[i];
    50             for(int j = i ; j >= 0 ; j--) 
    51             {
    52                 if(E[j] > begin) continue;
    53                 if(dp[E[j]] > dp[seek])
    54                 {
    55                     seek = E[j];
    56                 }
    57              }
    58              dp[end] = max(dp[end] , dp[seek] + V[i]);
    59             dpmax = max(dp[end],dpmax);
    60         }
    61         cout << dpmax << endl;
    62     }
    63     return 0;
    64 }

    综上可得复杂为 O(n^2) 不够好。

    是否可以降低复杂度 ?

    可以,可以定义dp[w] 为时间点 w 以前 做事件所能得到的最大价值。这样就可以每次查找第 i 件事前的第一个dp不为0的值,进行状态转移。

    如何更新 dp 数组 ?设第 i 件事结束时间为 end , 向前搜索 第一个 dp 值不为 0 的值 。 保留大的数,储存在 dp[end] 中 。

    但是这样不一定能降低很多的时间。

    最坏情况是 :

      第 n 件事 开始 时间点 是 第 n 小 , 结束时间 是 第 n 大 。

    ( 第一件事 的开始时间最大,结束时间最晚)

    (第二件事 的开始时间第二大,结束时间倒数第二晚)

    (。。。。。。。。。。。。。。。。。。。。)

    这样平摊下去,仍然是 n ^ 2.

  • 相关阅读:
    小波变换的引入,通俗易懂
    Leetcode 437. Path Sum III
    Leetcode 113. Path Sum II
    Leetcode 112 Path Sum
    Leetcode 520 Detect Capital
    Leetcode 443 String Compression
    Leetcode 38 Count and Say
    python中的生成器(generator)总结
    python的random模块及加权随机算法的python实现
    leetcode 24. Swap Nodes in Pairs(链表)
  • 原文地址:https://www.cnblogs.com/ticsmtc/p/4984711.html
Copyright © 2011-2022 走看看