标签:
题目:
有 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.
标签:
原文地址:http://www.cnblogs.com/ticsmtc/p/4984711.html