嘘~ 正在从服务器偷取页面 . . .

洛谷P4046 [JSOI2010]快递服务 题解


洛谷P4046 [JSOI2010]快递服务 题解

题目链接:P4046 [JSOI2010]快递服务

题意

「飞奔」快递公司成立之后,已经分别与市内许多中小企业公司签订邮件收送服务契约。由于有些公司是在同一栋大楼内,所以「飞奔」公司收件的地点(收件点)最多只有 \(m\) 点(\(1,2,\dots,m\)),因此「飞奔」仅先行采购了三辆货车并聘用了三名司机,每天早上分别从收件地点 \(1,2,3\) 出发。而在与客户的服务契约中有明确订约:「飞奔」必须在客户提出邮件寄送要求的隔天派人至该公司(地点)收件。

为了能更有效率的服务客户并节省收件时间,该公司设立了收件服务登记网站,客户如有邮件需要寄送,必须在需要收件的前一天就先上网登记。为了节省油量,「飞奔」就利用晚上先行安排三位司机隔天的收件路线。每位司机至各地点收件的顺序应与各公司上网登记的顺序相符且必须能在最省油的情况下完成当天所有的收件服务。因此每位司机有可能需要在不同时间重复到同一地点收件,或不同的司机有可能需在不同的时间点前往同一地点收件。

如下面范例二(收件公司地点依序为:4 2 4 1 5 4 3 2 1)所示,虽然司机 \(1\) 一开始就已经在收件地点 \(1\) 了,但是他却不能先把后面第四个登记的公司(地点 \(1\))邮件先收了再前往第一、第二、或第三个登记收件地点(地点 \(4,2,4\))收件。但是如果前三个登记收件的服务是由司机 \(2\)\(3\) 来负责,则司机 \(1\) 就可以在地点 \(1\) 收了第四个登记的邮件后再前往后面所登记的地点收件。此外,在某些情况下,不一定每辆车都要收到货,也就是说,最佳收件方式也有可能是只需出动一或两辆车去收货。请写一个程序来帮「飞奔」公司计算每天依预约顺序至各收件地点收件的最少总耗油量。

输入格式

输入文件第一行有一个整数 \(m\),代表「飞奔」公司收件的地点数,以 \(1\)\(m\) 之间的整数代号来表示每个地点。

接下来的 \(m\) 行(第 \(2\) 到第 \(m+1\) 行),每行有 \(m\) 个整数,代表一个矩阵 \(D\)。第 \(i\) 行的第 \(j\) 个整数 \(D(i,j)\) 表示司机开车从收件点 \(i\) 到收件点 \(j\) 所需耗油量。最后一行是一个序列,按照顺序为前一天上网登记要求收件的公司地点代号,最多会有 \(1000\) 个收件请求。

输入文件中任两个相邻的整数都以一个空格隔开。

注意:油量矩阵 \(D\) 满足三角不等式,也就是说 \(\forall 1 \leq i,j,k \leq m,D(i,j) \leq D(i,k)+D(k,j)\)。因此,每辆车前往下一个收件地点时一定是直接前往,不必先绕道至其它地点再抵达下个收件地点。

输出格式

输出一个整数,代表收件所需最少总耗油量。

数据范围

\(3 \leq m \leq 200,1 \leq s_i \leq m\)

这个题感觉几年前做过两个人的,现在三个人其实只要再加一维就好了。

\(f(i,x,y)\) 表示两个人在 \(x\)\(y\) ,还有个在 \(a_i\) 时的最小花费。考虑刷表法转移 \[ \begin{aligned} f(i+1,x,y) \downarrow f(i,x,y) + g(a_i, a_{i+1}) \\[6pt]f(i+1,a_i,y) \downarrow f(i,x,y) + g(x,a_{i+1}) \\[6pt]f(i+1,x,a_i) \downarrow f(i,x,y) + g(y,a_{i+1}) \end{aligned} \] 时间复杂度 \(\mathcal{O}(nm^2)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e3 + 15))
#define M ((int)(205))

int n,m,a[N],f[2][M][M],g[M][M];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> m;
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= m; j++) cin >> g[i][j];
    for(int i = 1; cin >> a[i]; n = i++);
    memset(f[0], 0x3f, sizeof(f[0]));
    f[0][1][2] = 0; a[0] = 3;
    for(int i = 0, cur, nxt; i < n; i++)
    {
        cur = i & 1; nxt = cur ^ 1;
        memset(f[nxt], 0x3f, sizeof(f[nxt]));
        for(int x = 1; x <= m; x++)
            for(int y = 1; y <= m; y++)
            {
                if(x == a[i] || x == y || y == a[i]) continue;\
                down(f[nxt][a[i]][y], f[cur][x][y] + g[x][a[i + 1]]);
                down(f[nxt][x][a[i]], f[cur][x][y] + g[y][a[i + 1]]);
                down(f[nxt][x][y], f[cur][x][y] + g[a[i]][a[i + 1]]);
            }
    }
    int res = INF;
    for(int i = 1; i <= m; i++)
        for(int j = 1; j <= m; j++) {
            if(i == j || i == a[n] || j == a[n]) continue;
            down(res, f[n & 1][i][j]);
        }
    cout << res << '\n';
    return 0;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录