洛谷 P1280 尼克的任务+上网

该博客介绍了洛谷P1280题目——尼克的任务,这是一个涉及动态规划的编程问题。博主分析了题目背景,解释了如何理解成线段覆盖问题,并给出了状态转移方程。通过示例,博主详细阐述了如何找到最大化快乐程度的上网安排,同时指出本题与另一题目的解题思路相似,但需要注意不同之处在于时间区间的不可叠加。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:洛谷 P1280 尼克的任务

分析:

本题是一道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;    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值