分析:
本题是一道DP题,我们可以把它看成是一个类似与线段覆盖的题目,只是最后给出的答案是用整个长度减去最大覆盖长度即可。
考虑一下DP方程:f[i]表示在从n到i这段时间中最少的休息时间;
两个状态更新:一个是当前时刻i没有在开始进行的工作,那么就f[i]=f[i+1]+1;(此过程从n到1倒推)
另一个便是如果当前i时刻有开始工作的任务,那么就从多个中选择一种能够所需的最大时间f[i]=max(f[i],f[i+m[now].la])(.la表示的终止时间)
注意这里1~3与3~5是可以同时覆盖成1~5。
程序代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int now;
struct miss{ int st; int la;};//st表示的是开始时间,la表示的是开始往后多少时间
bool cmp(miss a,miss b){ return a.st>b.st;}//排序
struct miss m[10001];
int mis[10001];
int f[10001];
int n,k;
int main(){
cin>>n>>k;
for(int i=1;i<=k;i++){
cin>>m[i].st>>m[i].la;
mis[m[i].st]++;//存下相同开始时间的个数
}
sort(m+1,m+1+k,cmp);//按照开始时间的大小排序
for(int i=n,now=1;i>=1;i--){
if(!mis[i]) f[i]=f[i+1]+1;//如果没有开始的工作,那就将休息时间+1
else for(int k=1;k<=mis[i];k++,now++) f[i]=max(f[i],f[i+m[now].la]);
//如果有开始的工作,那就从f[i]和f[i+m[now].la]中选择最大的即可
}
cout<<f[1];
return 0;
}
上网
(这题是本校在洛谷上的团队题,不好给链接,所以就给个题面吧)
题目描述
假设有n个人要上网,却只有1台电脑可以上网。上网的时间是从1 szw 至 T szw ,szw是一个自创的时间单位,至于 szw怎么换算成s,min或h,没有人清楚。依次给出每个人在某个时间段内上网的快乐程度C(必须这个人在整个时间段内都在上网,才能获得快乐程度C,否则,快乐程度是0),请你得到使总的快乐程度达到最大的方案。
输入输出格式
输入格式:
第1行2个整数 n和T,含义如题目所述;
接下来有n个这样的结构(每两个相邻的结构之间有一空行,且第1个结构和第一行间有一空行):
第1行一个整数Mi,表示第i个人的时间段的个数;
接下来有Mi行,每行3个整数Xj,Yj,C,表示第i个人在[Xj,Yj]内上网的快乐程度为C,
因此有Xj-Yj-1=1,X1=1,Ymi=T,Xj<=Yj。
输出格式:
仅输出一行,为总的最大的快乐程度。
输入样例
3 10
3
1 3 6
4 7 9
8 10 3
3
1 3 5
4 7 10
8 10 1
4
1 3 2
4 8 2
9 9 6
10 10 3
输出样例
25
【样例说明】
在[1,3]内,安排1上网,快乐程度为6;
在[4,7]内,安排2上网,快乐程度为10;在[8,8]内,不安排;
在[9,9]内,安排3上网,快乐程度为6;
在[10,10]内,安排3上网,快乐程度为3;
这是使总的快乐程度达到最大的方案,对应的值是25。
【数据范围】
对于30%的数据,n<=4,所有的Mi<=5,T<=20;
对于60%的数据,n<=100,所有的Mi<=100,T<=2000;
对于100%的数据,n<=500,所有的Mi<=500,T<=500000,所有的0
题目分析:
本题之所以放在上面那题的下面,是因为本蒟蒻做这题的时候想到跟上面类似的做法。
在上一题中,我们用f[i]表示了i到n的休息最小值,在这里我想用来表示i到n能够获取的总的最大快乐程度。详见代码。本题要注意的是像上面所讲的1~3和3~5不能合成1~5,因为在这道题中,1~3表示是将这段时间都霸占了,3这个时刻不能再用了。
程序代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int now,n,tt,tot,t;
struct ar1{ int st,ed,w;}m1[250001],m[250001];//st开始时间,ed结束时间,w存的是价值
bool cmp(ar1 a,ar1 b){return a.st>b.st;}
int mis[5000001],f[5000001];//mis[i]表示在时间i时开始的任务数
inline int read(){//读入优化
int x=0,w=1;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch-48),ch=getchar();
return x*w;
}
int main(){
freopen("T747.in","r",stdin);
freopen("T747.out","w",stdout);
n=read();t=read();
for(register int k=1;k<=n;++k){
int mm=read();
for(register int i=1;i<=mm;++i){
m1[++tt].st=read(); m1[tt].ed=read(); m1[tt].w=read();
}//先将数据读入
}
sort(m1+1,m1+1+tt,cmp);//按照开始时间排序
for(register int i=1;i<=tt;++i)
if(m1[i].st!=m[tot].st||m1[i].ed!=m[tot].ed) m[++tot].st=m1[i].st,m[tot].ed=m1[i].ed,m[tot].w=m1[i].w,mis[m1[i].st]++;
else if(m1[i].w>m[tot].w) m[tot].w=m1[i].w;
//这里主要是去重操作,根据样例,会有很多重复的数据,
//例如他可能会给你1 3 1,1 3 2,1 3 3之类的,这样有用的就只有1 3 3,
//所以去掉,并且会给以后的操作腾时间出来。
for(register int i=t,now=1;i>=1;--i){
if(!mis[i]) f[i]=f[i+1];
else{
for(register int k=1;k<=mis[i];++k,++now){
f[i]=max(max(m[now].w+f[m[now].ed+1],f[i+1]),f[i]);
//将m[now].w+f[m[now].ed+1],f[i+1]),f[i]这三个取max
//至于为什么,自己可以好好想想
}
}
}
printf("%d\n",f[1]);//最后输出
return 0;
}