【2018NOIP普及组】T3 摆渡车

P5017 摆渡车
题目传送门
思路:

  1. 对于每一个人他的最长等待时间为m-1。车刚走,他下分钟到。
  2. f[i][j]表示第i个人等j分钟的所有人的最小等待时间(最优解)。注意:第i个人等0分钟(他来就开车),不一定是最优的。
  3. 深搜第i人在开车时间为st时得最优解,把它的值赋给f[i][st-a[i]]; (记忆化)
  4. 第i个人在开车时间为st时,这班车上(车)的人总等待时间=st*(j-i)-sum;sum为上车的人到达时间和。然后再加上第j个人,开车时间为(st+m)的最优值(dfs(j,st+m),我们就初步得到一个最优解(不一定是最优的)
  5. 接下来对于best,我们还需更新最优值;(如果 第i个人后还有人没上车,那么以st为开车时间不一定是最优的)这里我给出一种情况,大家就比较好理解了。只有2个人,第一个1分钟时到,第二个人2分钟到,m=10,st=1并不是最优的。
    要想不超时,记忆化+剪枝是法宝!
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=5e2+5;
int a[N],f[N][N],n,m;
//f[i][j] 表示第i个人等待j分钟时,所有人的最少等待时间; 
void input()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+1+n);
}
int dfs(int i,int st)
{  
	//记忆化搜索。i:第i个人,st:开车时间
	if(i>n)     return 0; //所有人都搞定了
	if(st<a[i]) return dfs(i,a[i]);
	//如果现在的时间没有人,就到下一个人的到达时间
	if(f[i][st-a[i]]) return f[i][st-a[i]];
	int sum=0,j=i; //车等人 	
	while(j<=n&&a[j]<=st) sum+=a[j++];
	int best=st*(j-i)-sum+dfs(j,st+m);
	//人等车
	for(;j<=n;j++)
	{
		sum+=a[j];
		best=min(a[j]*(j-i+1)-sum+dfs(j+1,a[j]+m),best);
	}
	return f[i][st-a[i]]=best; //记忆化 
}
int main()
{
	//fre();
	input();
	cout<<dfs(1,a[1]);
	return 0;
}

原创文章 157 获赞 148 访问量 8309

猜你喜欢

转载自blog.csdn.net/bigwinner888/article/details/105822921