P4046-[JSOI2010]快递服务
题目:
题目描述:
「飞奔」快递公司成立之后,已经分别与市内许多中小企业公司签订邮件收送服务契约。由于有些公司是在同一栋大楼内,所以「飞奔」公司收件的地点(收件点)最多只有m点 (1, 2, …, m),因此「飞奔」仅先行采购了三辆货車并聘用了三名司机,每天早上分别从收件地点 「1」, 「2」 及 「3」出发。而在与客户的服务契约中有明确订约:「飞奔」必须在客户提出邮件寄送要求的隔天派人至该公司(地点)收件。
为了能更有效率的服务客户并节省收件时间,该公司设立了收件服务登记网站,客户如有邮件需要寄送,必须在需要收件的前一天就先上网登记。为了节省油量,「飞奔」就利用晚上先行安排三位司机隔天的收件路线。每位司机至各地点收件的顺序应与各公司上网登记的顺序相符且必须能在最省油的情况下完成当天所有的收件服务。因此每位司机有可能需要在不同时间重复到同一地点收件,或不同的司机有可能需在不同的时间点前往同一地点收件。
如下面范例二(收件公司地点依序为: 4 2 4 1 5 4 3 2 1)所示,虽然司机1一开始就已经在收件地点「1」了,但是他却不能先把后面第四个登记的公司(地点「1」)邮件先收了再前往第一、第二、或第三个登记收件地点(地点「4」, 「2」, 「4」)收件。但是如果前三个登记收件的服务是由司机2或3來负责,则司机1就可以在地点「1」收了第四个登记的邮件后再前往后面所登记的地点收件。此外,在某些情况下,不一定每辆车都要收到货,也就是說,最佳收件方式也有可能是只需出动一或兩辆车去收货。请写一个程序來帮「飞奔」公司计算每天依预约顺序至各收件地点收件的最少总耗油量。
输入格式:
输入文件第一行有一个整数 m($3 \leq m \leq 200$),代表「飞奔」公司收件的地点数,以1至m之间的整数代号來表示每个地点。
接下來的m行(第2到第m+1行),每行有m个整数,代表一个矩阵D。第 i +行的第 j 个整数是D(i, j),D(i, j) 代表司机开车从收件点 i 到收件点 j 所需耗油量。最后有一行数串,数串之数字依序为前一天上网登记要求收件的公司地点代号,最多会有1000个收件请求。输入文件中任兩个相邻的整数都以一个空白隔开。
注意:油量矩阵D满足三角不等式,也就是说 $D(i, j) \leq D(i, k) + D(k, j),1 \leq i, j, k \leq m$。因此,每辆车前往下一个收件地点时一定是直接前往,不必先绕道至其它地点再抵达下个收件地点。
输出格式:
输出一个整数,代表收件所需最少总耗油量。
样例:
样例输入1:
1
2
3
4
5
6
7
|
4
0 5 0 6
6 0 5 6
1 6 0 6
1 1 1 0
1 1 1 1 4 4 2 2 2 3
|
样例输出1:
思路:
记$f_{i, j, k}$表示签收完前$i$个后另外两辆车的位置即可转移.
实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
| // Problem: P4046 [JSOI2010]快递服务
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4046
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Ybw051114
//
// Powered by CP Editor (https://cpeditor.org)
#include "ybwhead/ios.h"
const int maxn = 1010, maxm = 210;
int d[maxm][maxm], f[2][maxm][maxm];
int n, m, a[maxn];
int main()
{
yin >> m;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++)
yin >> d[i][j];
a[++n] = 1;
a[++n] = 2;
a[++n] = 3;
while (yin >> a[++n])
;
--n;
// cerr << "!!!" << endl;
memset(f, 0x3f3f3f3f, sizeof(f));
f[1][2][1] = 0;
for (int i = 3; i < n; i++)
{
int tt = !(i & 1), nw = i & 1;
memset(f[tt], 0x3f3f3f3f, sizeof(f[tt]));
for (int j = 1; j <= m; j++)
{
for (int k = 1; k <= m; k++)
{
// cerr << m << endl;
f[tt][j][k] = min(f[tt][j][k], f[nw][j][k] + d[a[i]][a[i + 1]]);
f[tt][a[i]][k] = min(f[tt][a[i]][k], f[nw][j][k] + d[j][a[i + 1]]);
f[tt][a[i]][j] = min(f[tt][a[i]][j], f[nw][j][k] + d[k][a[i + 1]]);
}
}
// cerr << "!!!" << endl;
}
// cerr << "!!!" << endl;
int ans = INT_MAX;
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++)
ans = min(ans, f[n & 1][i][j]);
yout << ans << endl;
return 0;
}
|