EOJ1600公路巡逻

单点时限: 10.0 sec
内存限制: 256 MB
在一条没有分岔的高速公路上有 n 个关口,相邻两个关口之间的距离都是 10km。所有车辆在这条高速公路上的最低速度为 60km/h,最高速度为 120km/h,并且只能在关口处改变速度。
巡逻的方式是在某个时刻 Ti 从第 ni 个关口派出一辆巡逻车匀速驶抵第 (ni+1) 个关口,路上耗费的时间为 ti 秒。
两辆车相遇是指它们之间发生超车或者两车同时到达某关口(同时出发不算相遇)。
巡逻部门想知道一辆于 6 点整从第 1 个关口出发去第 n 个关口的车(称为目标车)最少会与多少辆巡逻车相遇,请编程计算之。假设所有车辆到达关口的时刻都是整秒。
输入格式
输入第一行为两个用空格隔开的整数,分别为关口数 n 和巡逻车数 m。(1<n<50,1<m<300),接下来的 m 行每一行为一辆巡逻车的信息(按出发位置递增排序),格式为 ni Ti ti,三项用空格隔开,分别表示第 i 辆巡逻车的出发位置、出发时刻和路上耗费的时间,其中 ni 和 ti 为整数,Ti 形如 hhmmss,表示时、分、秒,采用 24 小时制,不足两位的数用前置 0 补齐。(1<=ni<n,05:00:00<=Ti<=23:00:00,300<=ti<=600)
输出格式
输出文件第一行为目标车与巡逻车相遇次数。第二行为目标车与巡逻车相遇次数最少时最早到达第 n 个关口的时刻(格式同输入中的 Ti)
样例
input
3 2
1 060000 301
2 060300 600
output
0
061301

第一次看这个题感觉应该是DP,然后考虑了很多种写法,但是一直因为担心自己的写法不够优秀会TLE所以很纠结
后来发现只要把巡逻车辆按照出发点分开时间就差不多了,比我想象的要简单
至于如何判断相遇——画个x-t函数图像你自己就明白了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define rt long long
using namespace std;
inline rt read()
{
    register rt u=0,v=1;register char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')v=-1;ch=getchar();}
    while(isdigit(ch)){u=u*10+ch-'0';ch=getchar();}
    return u*v;
}
struct car
{
    rt start,when,time;
}an[310];
char as[10];
rt dp[55][86400],L[55],R[55],n,m;
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)L[i]=m+1;
    for(int i=1;i<=m;i++)
    {
         an[i].start=read();
         scanf("%s",as+1);
         an[i].when=((as[1]-'0')*10+as[2]-'0')*3600+((as[3]-'0')*10+as[4]-'0')*60+(as[5]-'0')*10+as[6]-'0';
         an[i].time=read();
         L[an[i].start]=min(L[an[i].start],1LL*i);
         R[an[i].start]=max(R[an[i].start],1LL*i)}
    memset(dp,0x3f,sizeof(dp));
    dp[1][21600]=0;
    for(int i=1;i<n;i++)
         for(int j=21600;j<86400;j++)
         if(dp[i][j]!=dp[0][0])
         {
             for(int k=300;k<=600;k++)
            {
		     if(j+k>=86400)break;
		     rt sum=0;
		     for(int s=L[i];s<=R[i];s++)
		     if((j+k==an[s].when+an[s].time)||(j+k>an[s].when+an[s].time&&j<an[s].when)||(j+k<an[s].when+an[s].time&&j>an[s].when))sum++;
		     dp[i+1][j+k]=min(dp[i+1][j+k],dp[i][j]+sum);
	    }
          }
    rt minn=dp[0][0],ans;
    for(int i=21600;i<86400;i++)
    if(dp[n][i]<minn)minn=dp[n][i],ans=i;
    printf("%lld\n",minn);
    rt hour=ans/3600;
    ans%=3600;
    rt minute=ans/60;
    ans%=60;
    printf("%02d%02d%02d",hour,minute,ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值