[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;
}
posted @ 2018-11-28 11:35  sdzwyq  阅读(315)  评论(0编辑  收藏  举报