【Uva12222】CQYZ_Vijos_P3179 山路

来源:互联网 发布:个人域名企业备案 编辑:程序博客网 时间:2024/05/01 05:01

【问题描述】

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