• 项目安排(离散化+DP)


    题目来源:网易有道2013年校园招聘面试二面试题
    题目描述:

    小明每天都在开源社区上做项目,假设每天他都有很多项目可以选,其中每个项目都有一个开始时间和截止时间,假设做完每个项目后,拿到报酬都是不同的。由于小明马上就要硕士毕业了,面临着买房、买车、给女友买各种包包的鸭梨,但是他的钱包却空空如也,他需要足够的money来充实钱包。万能的网友麻烦你来帮帮小明,如何在最短时间内安排自己手中的项目才能保证赚钱最多(注意:做项目的时候,项目不能并行,即两个项目之间不能有时间重叠,但是一个项目刚结束,就可以立即做另一个项目,即项目起止时间点可以重叠)。

    输入:

    输入可能包含多个测试样例。
    对于每个测试案例,输入的第一行是一个整数n(1<=n<=10000):代表小明手中的项目个数。
    接下来共有n行,每行有3个整数st、ed、val,分别表示项目的开始、截至时间和项目的报酬,相邻两数之间用空格隔开。
    st、ed、value取值均在32位有符号整数(int)的范围内,输入数据保证所有数据的value总和也在int范围内。

    输出:

    对应每个测试案例,输出小明可以获得的最大报酬。

    样例输入:
    3
    1 3 6
    4 8 9
    2 5 16
    4
    1 14 10
    5 20 15
    15 20 8
    18 22 12
    样例输出:
    16
    22

    思路:
    这题初看和01背包问题类似,不同的是这里的开始和截止时间没有明确的上限,所以直接用01背包问题来做肯定是有问题的。这道题给出的上限就是项目的个数最大为10000,我们可以从这个分析,表示时间的状态最多有20000种。所以我们必须对每个项目的开始和截止时间进行离散化到0~20000之间,这样就把问题转化到01背包了。
    定义dp[x],表示截止到时间x,小明可以获得的最大报酬。状态转移方程为:
      dp[x] = max{dp[x - 1], dp[l]} (l为项目的截止时间为x的开始时间)
    对于离散化,可以对项目中出现的开始和截止时间存入set容器进行排序,排序后的各时间在容器中的下标就是它们的离散化值,用这些离散化值来更高对于的项目开始和截止时间就完成了对时间的离散化。
    具体代码如下:
     1 #include <iostream>
     2 #include <set>
     3 #include <map>
     4 using namespace std;
     5 
     6 typedef struct _task_t
     7 {
     8     int st, sd, value;
     9 }task_t;
    10 
    11 set<int> index_map; //用于下标的离散化
    12 map<int, int> index_map_map; //存放离散化的结果
    13 task_t task_data[10005]; //存放输入数据
    14 multimap<int, task_t *> task_map; //用于任务的映射
    15 int dp[20005]; //用于dp
    16 int n; //任务的个数
    17 int max_proj; //任务的最大时间
    18 
    19 #define max(a, b) (a >= b ? a : b)
    20 int main(void)
    21 {
    22     int i;
    23     pair<multimap<int, task_t *>::iterator, multimap<int, task_t *>::iterator> pos;
    24     task_t *temp;
    25 
    26 //    freopen("in.txt", "r", stdin);
    27     while (cin >> n)
    28     {
    29         index_map.clear();
    30         index_map_map.clear();
    31         task_map.clear();
    32         for (i = 1; i <= n; i ++)
    33         {
    34             cin >> task_data[i].st >> task_data[i].sd >> task_data[i].value;
    35             index_map.insert(task_data[i].st);
    36             index_map.insert(task_data[i].sd);
    37         }
    38         i = 0;
    39         set<int>::iterator iterator_index = index_map.begin();
    40         for (; iterator_index != index_map.end(); iterator_index++)
    41             index_map_map.insert(map<int, int>::value_type(*iterator_index, i++));
    42         max_proj = i;
    43         for (i = 1; i <= n; i ++)
    44         {
    45             task_data[i].st = index_map_map[task_data[i].st];
    46             task_data[i].sd = index_map_map[task_data[i].sd];
    47             task_map.insert(multimap<int, task_t *>::value_type(task_data[i].sd, &task_data[i]));
    48         }
    49         dp[0] = 0;
    50         for (i = 1; i < max_proj; i ++)
    51         {
    52             pos = task_map.equal_range(i);
    53             dp[i] = dp[i - 1];
    54             for (; pos.first != pos.second; pos.first++)
    55             {
    56                 temp = (pos.first)->second;
    57                 dp[i] = max(dp[i], dp[temp->st] + temp->value);
    58             }
    59         }
    60         cout << dp[max_proj - 1] << endl;
    61     }
    62     return 0;
    63 }
    View Code
    总结:第一次在A题的时候用C++的STL库,表示很强大!!!!
  • 相关阅读:
    洛谷 P1653 猴子 解题报告
    洛谷 P2024 [NOI2001]食物链 解题报告
    洛谷 P1966 火柴排队 解题报告
    洛谷 P1311 选择客栈 解题报告
    洛谷 P3959 宝藏 解题报告
    二进制枚举子集技巧
    洛谷 P1841 [JSOI2007]重要的城市 解题报告
    洛谷 P2324 [SCOI2005]骑士精神 解题报告
    vector-size
    ubuntu 更换软件源
  • 原文地址:https://www.cnblogs.com/chengxuyuancc/p/3210515.html
Copyright © 2020-2023  润新知