码迷,mamicode.com
首页 > 其他好文 > 详细

(DP)最大价值事件序列选取

时间:2015-11-21 22:32:23      阅读:276      评论:0      收藏:0      [点我收藏+]

标签:

题目:

有 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.

 

(DP)最大价值事件序列选取

标签:

原文地址:http://www.cnblogs.com/ticsmtc/p/4984711.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!