【问题描述】
有一条狭窄的山路只有一个车道,因此不能有两辆相反方向的车同时驶入。另外,为了确保安全,对于山路上的任意一点,相邻的两辆同向行驶的车通过它的时间间隔不能少于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;
}