演讲大厅安排
Description
有一个演讲大厅需要我们管理,演讲者们事先定好了需要演讲的起始时间和中止时间。我们想让演讲大厅得到最大可能的使用。我们要接受一些预定而拒绝其他的预定,目标是使演讲者使用大厅的时间最长。假设在某一时刻一个演讲结束,另一个演讲就可以立即开始。
请依据演讲者的申请,计算出演讲大厅最大可能的使用时间
Input
第一行为一个整数 N,N≤5000,表示申请的数目。
以下 n 行每行包含两个整数 p,k,1 ≤ p < k ≤ 30000,表示这个申请的起始时间和终止时间。
Output
包含一个整数,表示大厅最大可能的使用时间。
Sample Input 1
12
1 2
3 5
0 4
6 8
7 13
4 6
9 10
9 12
11 14
15 19
14 16
18 20
Sample Output 1
16
这是一道基于时间轴的DP,也就是说,你只需要顺着时间轴走一遍就可以知道答案了;
首先存数据的方法与一般的直接存不同,只用存开始的时间点以及其持续的长度就可以了(值得注意的是一个时间点可以同时是几个演讲开始的时间点);
存数据是可以顺便将最后的一个时间点记下作为for循环的边界,然后开始DP;
每到下一个时间点,先判断是否继承上一个小时,再判断是否有演讲开始,如果有直接在演讲结束的时间点插入一个dp[i],表示到i小时最多的演讲时间,到后来for循环到了是自然会判断是否需要开始演讲(好像有点抽象),简单的说就是假设每个演讲都批准,又同时假设不批准,因为批准的情况是直接插入的,所以对于中间的时间没有影响,而到了演讲结束的时候再判断;
这样讲起来可能太抽象,还是上代码:
#include<bits/stdc++.h>
using namespace std;
int n,sj,dp[30001],t[30001],ma[100][30001];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int x,y;
cin>>x>>y;
ma[++t[x]][x]=y-x;//每个时间点的每个开始的演讲的持续时间
sj=max(sj,y);//最长的持续时间
}
for(int i=0;i<=sj;i++)
{
dp[i]=max(dp[i],dp[i-1]);//判断是原来插入的时间好还是继承上一小时的好
int tmp=1;
while(ma[tmp][i]!=0)//枚举这个点开始的每个演讲
{
dp[i+ma[tmp][i]]=max(dp[i+ma[tmp][i]],dp[i]+ma[tmp][i]);//判断是否插入
tmp++;
}
//cout<<i<<" "<<dp[i]<<endl;
}
cout<<dp[sj];
}
如果还有点懵逼可以做一做“饥饿的奶牛”;