题解 P5017 【摆渡车】

· · 题解

考场上送我退役的题目,因为这题目没发现t4是搜索水题。

这个题如果15分钟之内写出来说明dp的水平很强了。

首先先说一下……贪心一般都能被考场上的大样例hack了,高级贪心应该也过不去。

看到没有人发记忆化搜索的方法我就补一下,代码也很简短。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>

using namespace std;

int read()
{
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}

int n,m,t[505],mem[505][505];

//因为0<=st-t[i]<=m,因此可以记忆化,把这个作为状态的第二维 

int solve(int i,int st)//记忆化搜索。i:第i个人,st:开始时间st 
{
    if (i==n+1)//所有人都上车了 
        return 0;
    if (st<t[i])//如果现在的时间没有人,就到下一个人的到达时间 
        return solve(i,t[i]);
    if (mem[i][st-t[i]])//记忆化 
        return mem[i][st-t[i]];
    int sum=0,j=i;
    //车等人 
    while (j<=n && t[j]<=st)
        sum+=t[j++];
    int best=st*(j-i)-sum+solve(j,st+m); 
    //人等车
    for (;j<=n;j++)
    {
        sum+=t[j];
        best=min(t[j]*(j-i+1)-sum+solve(j+1,t[j]+m),best);
    }
    return mem[i][st-t[i]]=best;
}

int main()
{
    //memset(mem,-1,sizeof(mem));
    n=read(),m=read();
    for (int i=1;i<=n;i++)
        t[i]=read();
    sort(t+1,t+n+1);//显然从小到大按照时间排序更好算 
    cout << solve(1,0) << endl;
    return 0;
}