【Uva12222】CQYZ_Vijos_P3179 山路

【问题描述】

  有一条狭窄的山路只有一个车道,因此不能有两辆相反方向的车同时驶入。另外,为了确保安全,对于山路上的任意一点,相邻的两辆同向行驶的车通过它的时间间隔不能少于10秒。
  给定n辆车的行驶方向、到达时刻(对于往右开的车来说是到达山的左端点的时刻,而对于往左开的车来说是指到达右端点的时刻),以及行驶完山路的最短时间(为了保证安全,实际行驶时间可以高于这个值),输出最后一辆车离开山路的最早时刻。输入保证任意两辆车的到达时刻均不相同。

【输入格式】

  第一行为数据组数c。每组数据的第一行为整数n,然后的n行,每行的数据表示车辆行驶方向(用A或B表示),到达时刻t,以及行驶完山路的最短时间d。(输入是按到达时间排好序的)

【输出格式】

  每组数据输出一行一个整数,表示你的答案。

【输入样例】

2
4
A 0 60
B 19 10
B 80 20
A 85 100
4
A 0 100
B 50 100
A 100 1
A 170 100

【输出样例】

200
270

【数据范围】

1 ≤ c ≤ 200
1 ≤ n ≤ 200
0 ≤ t ≤ 100 000
1 ≤ d ≤ 100 000

题解:

  教练说这道题是紫书上的原题,然而没有一个人A过。。。
  动态规划,设f(i,j,k)表示前i辆车,有j辆车从A开往B的情况,k=0表示最后一辆车从A开往B,k=1表示最后一辆车从B开往A
  状态转移:
  f(i,j,0)=min{f(i-x,j-x,1)+连续x辆车从A开往B的时间 | 1<=x<=j}
  f(i,j,1)=min{f(i-x,j,1)+连续x辆车从B开往A的时间 | 1<=x<=i-j}
  边界条件:
  f(0,0,0)=f(0,0,1)=0 , f(i,j,0)=f(i,j,1)=inf ( i!=0 || j!=0 )
  由于填表法需要用到之前的状态,时间复杂度O(n^4*T),很明显过不了,所以改用刷表法,动态维护连续x辆车通过的时间,时间复杂度O(n^3*T),可以A了~
  

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=205;
int n;
int At[maxn],Ad[maxn],Bt[maxn],Bd[maxn],cnta,cntb;
int d[maxn][maxn][2]={0};
int in(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-f;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int main(){
    int T=in();
    char op[5];
    while(T--){
        memset(d,127,sizeof(d));
        cnta=cntb=0;
        n=in();
        for(int i=1;i<=n;i++){
            scanf("%s",op);
            if(op[0]=='A') At[++cnta]=in(),Ad[cnta]=in();
            else Bt[++cntb]=in(),Bd[cntb]=in();
        }
        d[0][0][0]=d[0][0][1]=0;
        int st,mt,numb;
        for(int i=0;i<n;i++){
            for(int j=max(0,i-cntb);j<=i&&j<=cnta;j++){
                numb=i-j,st=mt=d[i][j][1];
                for(int x=j+1;x<=cnta;x++){
                    if(x==j+1) st=max(st,At[x]),mt=max(mt,st+Ad[x]);
                    else st=max(st+10,At[x]),mt=max(mt+10,st+Ad[x]);
                    d[i-j+x][x][0]=min(d[i-j+x][x][0],mt);
                }
                st=mt=d[i][j][0];
                for(int x=numb+1;x<=cntb;x++){
                    if(x==numb+1) st=max(st,Bt[x]),mt=max(mt,st+Bd[x]);
                    else st=max(st+10,Bt[x]),mt=max(mt+10,st+Bd[x]);
                    d[i-numb+x][j][1]=min(d[i-numb+x][j][1],mt);
                }
            }
        }
        printf("%d\n",min(d[n][cnta][0],d[n][cnta][1]));
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值