NOJ 1163 活动安排问题 [动态规划]

活动安排问题

时间限制(普通/Java) : 3000 MS/ 9000 MS 运行内存限制 : 65536 KByte
总提交 : 202            测试通过 : 55

比赛描述

设有n个活动的集合E={1,2,……,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si<fi。如果选择了活动i,则它在时间区间[si,fi]内占用资源。若区间[si,fi]与区间[sj,fj]不相交,则称活动i与活动j是相容的。也就是说,当si>=fj或者sj>=fi时,活动i与活动j相容。活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合。

但在现实生活中,不同的活动所带来的价值和意义是不一样的,所以我们可以为每个活动附上一个权值,现在的问题就是要在所给的活动集合中选出权值和最大的相容活动子集合。

输入

第一行输入一个正整数n(1<=n<=100000)为活动集合的大小 ,余下n行每行输入三个非负整数s,f,v分别代表活动的起始时间,结束时间和权值,(0<=s<f<=10000000 , 0<=v<=10000)。

输出

一行,权值和最大的相容活动子集合的权值和。

样例输入

3
0 5 50
6 9 49
3 7 100

样例输出

100

提示

题目来源

计算机学院/软件学院第二届ACM程序设计大赛

刚上完算法分析课程,刚看到还以为使用分支限界法求的带时限的作业排序,一看问题规模就打消了这个想法。老老实实用动态规划。

思路一:(超时代码)

首先按照时限排序。

dp[i] 表示时间为i时获得的的最大的价值,用背包的思想来考虑每一个活动。转移方程dp[i] = dp[job[k].s] + job[k].w

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;

struct Node
{
    int st;
    int en;
    int w;
    Node(int _st, int _en, int _w):st(_st), en(_en), w(_w) {}
};
bool cmp(Node a, Node b)
{
    return a.en < b.en;
}
vector<Node> Job;
int n,f=0;
int dp[10000010];
int read()
{
    int st,en,w;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d%d", &st, &en, &w);
        f=max(en,f);
        Job.push_back(Node(st,en,w));
    }
    sort(Job.begin(),Job.end(),cmp);
}

int main()
{
    read();
    for(int j = 0; j < n; j++)
    {
        for(int i = 0; i <= f; i++)
        {
            if(i >= Job[j].en)
                dp[i] = max(dp[i], dp[Job[j].st] + Job[j].w);
        }
    }
    cout<<dp[f]<<endl;
    return 0;
}


时间复杂度O(n f),超时

然后发现还是不能这样刻画状态,转变了下思路,dp[i]表示前i个活动中,第i个活动选所能带来的最大价值,在考虑第i+1个活动时,找到前i个活动能够满足结束时间早于第i+1个活动开始时间的最晚的活动。

状态转移方程 dp[i] = dp[j] + job[j].w // job[j].en < job[i].st

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <string.h>
using namespace std;

struct Node
{
    int st;
    int en;
    int w;
    Node(int _st, int _en, int _w):st(_st), en(_en), w(_w) {}
};
bool cmp(Node a, Node b)
{
    return a.en < b.en;
}
vector<Node> Job;
int n, f = 0;
int dp[1000010];
int read()
{
    int st, en, w;
    scanf("%d", &n);
    for(int i = 0; i < n; i++)
    {
        scanf("%d%d%d", &st, &en, &w);
        f=max(en, f);
        Job.push_back(Node(st, en, w));
    }
    sort(Job.begin(), Job.end(), cmp);
}

int main()
{
    read();
    for(int i = 0; i < n; i++)
    {
        int l = 0, r = i;
        while(l <= r)
        {
            int m = (l + r) >> 1;
            if(Job[m].en <= Job[i].st) l = m + 1;
            else r = m - 1;
        }
        dp[i] = max(dp[i-1], dp[l - 1] + Job[i].w);
    }
    cout << dp[n - 1] << endl;
    return 0;
}


在考虑动态规划时候,要思考描述的状态,勤加思考,考虑更好的方式。

时间: 2024-08-08 09:36:40

NOJ 1163 活动安排问题 [动态规划]的相关文章

活动选择问题 (动态规划 与 贪心算法)

问题描述: 设有n个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源.每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si <fi.如果选择了活动i,则它在半开时间区间[si, fi)内占用资源.若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的.也就是说,当si≥fj或sj≥fi时,活动i与活动j相容.活动安排问题就是要在所给的活动集合中选出最大的相容活动子集合. . 从图中

[C++] 贪心算法之活动安排、背包问题

一.贪心算法的基本思想 在求解过程中,依据某种贪心标准,从问题的初始状态出发,直接去求每一步的最优解,通过若干次的贪心选择,最终得出整个问题的最优解. 从贪心算法的定义可以看出,贪心算法不是从整体上考虑问题,它所做出的选择只是在某种意义上的局部最优解,而由问题自身的特性决定了该题运用贪心算法可以得到最优解.如果一个问题可以同时用几种方法解决,贪心算法应该是最好的选择之一. 二.贪心算法的基本要素 (1)最优子结构性质 (2)贪心选择性质(局部最优选择) 三.贪心算法实例 1.活动安排 设有n个活

51nod 1428 活动安排问题(优先队列)

1428 活动安排问题 首先按照开始时间从小到大排序. 其实只要维护一个结束时间的最小堆,每次比较开始时间和堆中最小时间的大小,如果比它大就放入堆中并且时间就要变成当前任务的结束时间, 否则就要新开一个教室.并且把结束时间加入堆中,注意判断堆是否为空. #include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; struct p

贪心算法_活动安排问题_哈弗曼编码

问题表述:设有n个活动的集合E = {1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源.每个活i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si < fi .如果选择了活动i,则它在半开时间区间[si, fi)内占用资源.若区间[si, fi)与区间[sj, fj)不相交,则称活动i与活动j是相容的.也就是说,当si >= fj或sj >= fi时,活动i与活动j相容. 由于输入的活动以其完成时间的非减序排列,所以算法

活动安排问题python实现

活动安排问题要求高效地安排一系列争用某一公共资源的活动,贪心算法提供了一个简单的方法,使尽可能多的活动能兼容地使用公共资源.贪心算法并不总能求得问题的整体最优解,但对于活动安排问题,贪心算法却能做到,使得最终所确定的相容活动集合的规模最大,证明不在这里给出.代码如下: def greedyManage(meeting): length=len(meeting) meeting.sort(key=lambda x:x[1]) result=[False for i in range(length)

hdu2037-----------贪心, 活动安排问题

http://acm.hdu.edu.cn/showproblem.php?pid=2037(简单贪心-----活动安排) #include<iostream> #include<algorithm> using namespace std; struct Node { int l, r; }a[105]; bool Cmp(Node x, Node y) { if(x.r!=y.r) return x.r<y.r; else return x.l>y.r; } int

贪心算法-----单线程:活动安排问题 多线程:多机调度问题

一.贪心算法的特点 顾名思义,贪心算法总是做出在当前看来是最好的选择.虽然贪心算法并不从整体最优上加以考虑,它所做出的选择只是在某种意义上的局部最优选择. 贪心算法的优点是更简单,更直接且解题效率更高,即使贪心算法不能得到整体最优解,但其最终结果却是最优解的很好的近似解. 二.贪心算法的理解 由于涉及到在做出在当前看来最好的选择,所以会经常采用排序算法,推荐使用快速排序算法,复杂度是O(nlgn),且在同等复杂度算法中效率是最高的, 本文涉及的排序都采用冒泡排序,只是注明需要排序而已. 贪心算法

忙碌的Nova君 (活动安排问题、贪心算法)

题目描述 理论上,Nova君是个大闲人,但每天还是有一大堆事要干,大作业啦,创新杯啦,游戏啦,出题坑人啦,balabala......然而精力有限,Nova君同一时间只能做一件事,并不能一心二用.假设现在有N项工作等待Nova君完成,分别在 Si 时刻开始,在 Ti 时刻结束,对于每项工作可以选择做或者不做,但不可以同时选择时间重叠的工作(即使是开始的瞬间和结束的瞬间重叠也是不允许的).Nova君自然希望尽量多做一些事情,那么最多能做几件事呢? 输入 多组测试数据(数据组数不超过10),对于每组

【算法导论实验5】贪心-活动安排问题与背包问题

首先是活动安排问题. 贪心的关键在于排序策略. 思路很简单,对所有活动的结束时间排序,如果结束时间相同,因为要尽量多的参加活动,所以选取开始时间尽量晚的(这样可以安排的比较多),然后依次从早到晚选取不冲突的活动加入,即为最多可以参加的活动. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <fstream> using n