ACM: 华东师范oj 1600&n…

这是一个关于计算在特定条件下,从第一个关口出发的目标车辆与巡逻车最少相遇次数的问题。题目描述了巡逻车从不同关口出发的时间和到达下一个关口的时间,以及车辆的速度范围。通过动态规划方法,可以求解目标车辆在最少相遇次数下最早到达最后一个关口的时间。

公路巡逻

Description

在一条没有分岔的高速公路上有n个关口,相邻两个关口之间的距离都是10km。所有车辆在这条高速公路上的最低速度为60km/h,最高速度为120km/h,并且只能在关口处改变速度。
巡逻的方式是在某个时刻Ti从第ni个关口派出一辆巡逻车匀速驶抵第(ni+1)个关口,路上耗费的时间为ti秒。
两辆车相遇是指它们之间发生超车或者两车同时到达某关口(同时出发不算相遇)。
巡逻部门想知道一辆于6点整从第1个关口出发去第n个关口的车(称为目标车)最少会与多少辆巡逻车相遇,请编程计算之。假设所有车辆到达关口的时刻都是整秒。

Input

输入第一行为两个用空格隔开的整数,分别为关口数n和巡逻车数m。(1<=ni<=Ti<=23:00:00,300<=ti<=600)

Output

输出文件第一行为目标车与巡逻车相遇次数。第二行为目标车与巡逻车相遇次数最少时最早到达第n个关口的时刻(格式同输入中的Ti)。

Sample Input

3 2
1 060000 301
2 060300 600

Sample Output

0
061301

题意: 你的车从6点整开始出发, 从1关口到n关口, 每次改变速度只可以在关口处(60km/h<=v<=120km/h),

      每个关口相距10km, 现在又m辆巡逻车, 给出每部巡逻车从ni关口出发的时间和到达下个关口的时间,

      现在要你求出在最少相遇次数下, 最早到达n关口的时间和相遇次数.

 

解题思路:

      1. 设dp[i][j]: 到达第i个关口时, 花费的时间为j与巡逻车相遇的最少次数.

         设time[j][j+k]: 时间j到j+k内相遇的次数.

         方程: dp[i+1][j+k] = min(dp[i+1][j+k], dp[i][j]+time[j][j+k]);

         结果: min(dp[n][i]);

 

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
#define MAX 305
#define MAXSIZE 52
const int INF = (1<<29);

struct node
{
 int start, end;
}car[MAX][MAX];

int n, m;
int dp[MAXSIZE][MAXSIZE*600];
int num[MAX];

inline int change(int time)
{
 int hour = time/10000;
 int min = (time/100)0;
 int second = time0;
 return ((hour-6)*60+min)*60+second;
}

inline int changeBack(int time)
{
 int second = time`;
 time /= 60;
 int min = time`;
 time /= 60;
 int hour = time+6;
 return (hour*10000)+min*100+second;
}

inline int min(int a, int b)
{
 return a < b ? a : b;
}

void DP()
{
 int i, j, k;
 dp[0][0] = 0;
 n--;
 for(i = 0; i < n; ++i)
 {
  for(j = i*300; j <= i*600; ++j)
  {
   for(k = 300; k <= 600; ++k)
   {
    int time = 0;
    for(int p = 0; p < num[i]; ++p)
    {
     if( (car[i][p].start >= j && car[i][p].end > j+k) ||
      (car[i][p].start <= j && car[i][p].end < j+k) )
      continue;
     else
      time++;
    }
    dp[i+1][j+k] = min(dp[i+1][j+k], dp[i][j]+time);
   }
  }
 }
}

int main()
{
 int i, j;
// freopen("input.txt", "r", stdin);
 while(scanf("%d %d", &n, &m) != EOF)
 {
  int ni, Ti, ti;
  for(i = 0; i < n; ++i)
   for(j = 0; j <= n*600; ++j)
    dp[i][j] = INF;

  memset(num, 0, sizeof(num));
  for(i = 0; i < m; ++i)
  {
   scanf("%d %d %d", &ni, &Ti, &ti);
   ni--;
   Ti = change(Ti);
   car[ni][ num[ni] ].start = Ti;
   car[ni][ num[ni] ].end = ti+Ti;
   num[ni]++;
  }

  DP();

  int result = INF;
  int time;
  for(i = n*300; i <= n*600; ++i)
  {
   if(result > dp[n][i])
   {
    result = dp[n][i];
    time = i;
   }
  }

  printf("%d\nd\n", result, changeBack(time));
 }
 return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值