题目大意:
题目链接:https://www.luogu.org/problemnew/show/P5017
有
n
n
n个人分别在
t
1
∼
t
n
t_1\sim t_n
t1∼tn的时间到达,一辆摆渡车要把这些人送到另外一个地方,摆渡车来回一次要
m
m
m的时间单位。求把这些人都送到的最短时间。
思路:
肯定可以先把
t
t
t排序。
我们知道,一个人到达后发车只会有两种情况:
- 摆渡车在他到达之前就到了。此时可以直接发车。
- 摆渡车在他到达后 k k k分钟才到。此时要等 k k k分钟才能发车。
可以先预处理出
s
[
i
]
[
j
]
s[i][j]
s[i][j],表示第
i
i
i个人到第
j
j
j个人做同一辆车的等待时间。那么就有
s
[
i
]
[
j
]
=
∑
j
=
1
n
∑
i
=
1
j
−
1
∑
k
=
i
j
−
1
t
j
−
t
k
s[i][j]=\sum^{n}_{j=1}\sum^{j-1}_{i=1}\sum^{j-1}_{k=i}t_j-t_k
s[i][j]=j=1∑ni=1∑j−1k=i∑j−1tj−tk
那么我们就设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示在
i
i
i个人到达后发车,第
i
i
i个人等了
j
j
j分钟时的最小等待时间。
那么肯定要枚举
j
j
j,表示前
j
j
j个人已经送到了目的地。
那么如果第
i
i
i个人到达时,摆渡车已经回来了,那么就可以直接发车(即第
i
i
i个人的等待时间为
0
0
0)。此时就有
f
[
i
]
[
0
]
=
m
i
n
(
f
[
i
]
[
0
]
,
f
[
j
]
[
k
]
+
s
[
j
+
1
]
[
i
]
)
f[i][0]=min(f[i][0],f[j][k]+s[j+1][i])
f[i][0]=min(f[i][0],f[j][k]+s[j+1][i])
其中
k
k
k表示枚举的第
j
j
j个人等待的时间。
那么如果第
i
i
i个人到达后摆渡车没有回来,那么第
i
i
i个人等待的时间就是
w
=
t
j
+
k
+
m
−
t
i
w=t_j+k+m-t_i
w=tj+k+m−ti
其中
t
j
+
k
+
m
t_j+k+m
tj+k+m是摆渡车回到的时间。
那么就有
f
[
i
]
[
w
]
=
m
i
n
(
f
[
i
]
[
w
]
,
f
[
j
]
[
k
]
+
s
[
j
+
1
]
[
i
]
+
(
i
−
j
)
∗
w
)
f[i][w]=min(f[i][w],f[j][k]+s[j+1][i]+(i-j)*w)
f[i][w]=min(f[i][w],f[j][k]+s[j+1][i]+(i−j)∗w)
答案就是
m
i
n
(
f
[
n
]
[
i
]
)
(
i
=
0
∼
m
)
min(f[n][i])(i=0\sim m)
min(f[n][i])(i=0∼m)
时间复杂度
O
(
n
2
m
)
O(n^2m)
O(n2m),足够过掉本题。
代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=510;
const int M=210;
const int Inf=2e9;
int n,m,ans,w,t[N],f[N][M],s[N][N];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&t[i]);
sort(t+1,t+1+n);
for (int j=1;j<=n;j++)
for (int i=1;i<j;i++)
for (int k=i;k<j;k++)
s[i][j]+=t[j]-t[k];
memset(f,0x3f3f3f3f,sizeof(f));
t[0]=-Inf;
for (int i=0;i<=m;i++) //初始化
{
f[0][i]=0;
f[1][i]=i;
}
for (int i=2;i<=n;i++)
for (int j=0;j<i;j++)
for (int k=0;k<=m;k++)
{
w=t[j]+k+m-t[i];
if (w>0)
f[i][w]=min(f[i][w],f[j][k]+s[j+1][i]+(i-j)*w);
else
f[i][0]=min(f[i][0],f[j][k]+s[j+1][i]);
}
ans=Inf;
for (int i=0;i<=m;i++)
ans=min(ans,f[n][i]);
printf("%d\n",ans);
return 0;
}