URAL1791 Uncle Styopa and Buses 贪心

关键词:任务安排、贪心、时间单调性(起始/截止时间随任务排序单调变化)
题意:a、b间有一条路径,每次只能有一辆车通行,每辆车通行时间为1分钟。已知准备好从a端出发车辆的时间t和该车通行该道路最多花费时间p,即该车在[t,t+p-1]时间内必须发车!b端同理。要求发车每一起点的发车顺序必须按照输入的顺序进行,输入顺序保证i< j,ti<=tj。
现在问是否有一种发车方案,使得每辆车都能顺利到达目的地。
解法:
1.从发车顺序条件出发:前一辆车的发车时间一定早于后一辆车,因此前一辆车的最晚发车时间一定早于后一辆车的最晚发车时间。因此: bus[i].lastbegin=min(bus[i].t+bus[i].p1,bus[i+1].lastbegin)
2.现在可得到同侧发车按顺序最早发车时间和最晚发车时间均递增。贪心思路:如果当前a-> b的最早发车时间为x1,最晚发车时间为x2,b->a的最早发车时间为y1,最晚发车时间为y2。
1)如果x1!=y1。那么小的那个先出发对大的不产生影响,因而对整体发车情况不产生影响。
2)如果x1==y1。x2!=y2时,一定小的先出发,因为每边的最晚发车时间都是递增的,所以x2和y2中小的最晚发车时间最靠前,因此需要先发车。
3)如果x1==y1&&x2==y2,这两辆车都需要在x2(或y2)之前发车,又因为剩下所有车的最晚发车时间都不小于x2(或y2),因此这两辆车都必须在剩下所有车发车之前发车,所以哪个先发车对能够成功安排通行的结果无影响!此时任意一个发车都可以。
现在问题是如何求当前车辆的最早和最晚发车时间?
最晚发车时间在1中已求出。求当前车辆的最早发车时间需要知道上次发车时间,因此需要用cur记录上次的发车时间,那么: bus[i].earlybegin=max(bus[i].t,cur+1).
本题难点在于想到维护上次发车时间,以及预处理每辆车的最晚发车时间

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<limits.h>
#include<queue>
#include<vector>
#define mem(a,b) memset(a,sizeof(a),b)
#define ll long long
#define MP make_pair
const ll INF = 0x0fffffffffffffff;
using namespace std;
typedef long long lld;

const int maxn = 100000+10;
/*
int read(){//读入优化 结果时间更长了。
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); }
    return x*f;
}*/

struct Node{
    int l,r;//l:最早出发时间;r:最晚出发时间
}bus1[maxn],bus2[maxn];
int n,m;

int Min(int a,int b){ return (a<b)?a:b; }
int Max(int a,int b){ return (a<b)?b:a; }

int main(){
    //freopen("a.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int dis;
        //bus1[i].l=read(),dis=read();
        scanf("%d%d",&bus1[i].l,&dis);
        bus1[i].r=bus1[i].l+dis-1;
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        int dis;
        //bus2[i].l=read(),dis=read();
        scanf("%d%d",&bus2[i].l,&dis);
        bus2[i].r=bus2[i].l+dis-1;
    }
    //计算每辆车的最晚出发时间---预处理很关键!
    for(int i=n-1;i>=1;i--) bus1[i].r=Min(bus1[i].r,bus1[i+1].r-1);
    for(int j=m-1;j>=1;j--) bus2[j].r=Min(bus2[j].r,bus2[j+1].r-1);
    int i,j;
    int cur=0;//记录上次的发车时间---以前的最晚发车时间(用来更新下次每辆车的最早发车时间)
    bool flag=true;
    for(i=1,j=1;i<=n&&j<=m;){
        if((cur+1>bus1[i].r)||(cur+1>bus2[j].r)){
            flag=false; break;
        }
        int tmpi=Max(cur+1,bus1[i].l),tmpj=Max(cur+1,bus2[j].l);//双向最早出发时间
        if(tmpi<tmpj) { cur=Max(cur+1,tmpi); i++; }
        else if(tmpi>tmpj) { cur=Max(cur+1,tmpj); j++; }
        else{
            if(bus1[i].r<bus2[j].r) { cur=Max(cur+1,tmpi); i++; }
            else { cur=Max(cur+1,tmpj); j++; }
        }
    }
    for(;flag&&i<=n;){
        if(cur+1>bus1[i].r) { flag=false; break; }
        cur=Max(cur+1,bus1[i].l);
        i++;
    }
    for(;flag&&j<=m;){
        if(cur+1>bus2[j].r) { flag=false; break; }
        cur=Max(cur+1,bus2[j].l);
        j++;
    }
    if(flag) printf("YES\n");
    else printf("NO\n");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值