[NOIP2018PJ]摆渡车

[NOIP2018PJ]摆渡车

luogu
mdPJ组这么难,还好考的TG组
先按t排序
设f[i][j]表示前i个人,第i个人等j分钟的最小总等待时间
这里j是小于2m的
可以考虑最坏情况下,一个人到起点时车刚好出发,m分钟之后回来
然后车又在起点停了m分钟等别人,则这个人一共等了2m分钟
转移分三种情况讨论:
下一个人赶上这趟车,即t[i+1]<=t[i]+j,那么转移到f[i+1][t[i]+j-t[i+1]]
下一个人在这趟车回来之前到了,即t[i+1]<=t[i]+j+m,枚举车回来后等待时间k,转移到f[i+1][t[i]+j+m-t[i+1]+k]
下一个人在这趟车回来之后才到,即t[i+1]>t[i]+j+m,直接枚举等待时间k,转移到f[i+1][k]

#include<bits/stdc++.h>
using namespace std;
int re(){
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
int n,m,ans,t[505],f[505][205];
void Min(int&x,int y){x=min(x,y);}
int main(){
    n=re(),m=re();
    for(int i=1;i<=n;i++)t[i]=re();
    sort(t+1,t+n+1);
    memset(f,63,sizeof(f));ans=f[0][0];
    for(int i=0;i<m*2;i++)f[1][i]=i;
    for(int i=1;i<n;i++){
        for(int j=0;j<m*2;j++){
            if(f[i][j]==ans)continue;
            if(t[i+1]<=t[i]+j)Min(f[i+1][t[i]+j-t[i+1]],f[i][j]+t[i]+j-t[i+1]);
            if(t[i+1]>t[i]+j+m){
                for(int k=0;k<m*2;k++)
                    Min(f[i+1][k],f[i][j]+k);
            }
            else{
                for(int k=0;t[i]+j+m-t[i+1]+k<m*2;k++)
                    Min(f[i+1][t[i]+j+m-t[i+1]+k],f[i][j]+t[i]+j+m-t[i+1]+k);
            }
        }
    }
    for(int i=0;i<m*2;i++)Min(ans,f[n][i]);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdzwyq/p/10031153.html