AcWing 274-移动服务 题解报告

动态规则02

Posted by Leo on February 21, 2023

AcWing 274 移动服务

题目大意

一个公司有三个移动服务员,最初分别在位置$1, 2, 3$

如果某个位置(用一个整数表示)有一个请求,那么公司必须指派某名员工赶到那个地方去。

某一时刻只有一个员工能移动,且不允许在同样的位置出现两个员工。

从$p$到$q$只有一个员工能移动,且不允许在同样位置又两个员工

花费函数不一定对称,保证$c(p, q) = 0$

给出$N$个请求,位置分别位$p_1 \sim p_N$

公司必须按顺序依次满足所有请求, 且过程中不能去其他额外的位置 ,目标是最小化公司花费,请你帮忙计算这个最小花费。

输入格式

第 $1$ 行有两个整数 $L,N$,其中 $L$ 是位置数量,$N$ 是请求数量,每个位置从 $1$ 到 $L$ 编号。

第 $2$至 $L+1$ 行每行包含 $L$ 个非负整数,为邻接矩阵,保证每个数$<2000$

最后一行包含 $N$个整数,是请求列表。

一开始三个服务员分别在位置 $1,2,3$。

输入样例

输出一个整数,表示最小花费。

数据范围

$3 \le L \le 200$

$ 1 \le N \le 1000 $

样例

Input:

5 9

0 1 1 1 1
1 0 2 3 2
1 1 0 4 1
2 1 5 0 1
4 2 3 4 0

4 2 4 1 5 4 3 2 1

Output:

5

题解

这题比较值得注意的思维是,它如果考虑状态怎么被转移过来的,即当一个员工在$t_j$时,考虑如何从$t_0 \sim t_{j-1}$转移过来($t_0$表示初始位置)比较复杂,但如果状态怎么转移走的就容易很多了,即$t_j$在紧接的状态更新时要不站着不动,要不走到$t_{j+1}$

并且三个员工显然是轮换对称的,以此可以设计以下状态$f_{i, j, k}$ 表示三人分别在$p_i, j, k$处时的最佳方案,则下一步可以分为三类

  • $p_i \rightarrow p_{i+1}$, 代价为 $f_{i+1, j, k} = f_{i, j, k} + c(p_i, p_{i+1})$
  • $j \rightarrow p_{i+1}$, 代价为$f_{i+1, p_i, k} = f_{i, j, k} + c(j, p_{i+1})$
  • $k \rightarrow p_{i+1}$, 代价为$f_{i+1, p_i, j} = f_{i, j, k} + c(k, p_{i+1})$

最后遍历 $f_{N, 1 \sim L, 1 \sim L}$找到min即可

参考代码

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
//
// Created by Leo on 2023/2/20.
//

// 用往后推的方法,即不找当前状态如何从以前的状态转移过来,而是考虑当前的状态如何推导到下一个状态
#include <bits/stdc++.h>

using namespace std;

const int MaxN = 1010, MaxL = 250;
int cost[MaxL][MaxL], tasks[MaxN];
int L, N, ans, f[MaxN][MaxL][MaxL];

int main() {
    cin >> L >> N;
    for (int i = 1; i <= L; i++)
        for (int j = 1; j <= L; j++)
            cin >> cost[i][j];
    for (int i = 1; i <= N; i++)
        cin >> tasks[i];
    memset(f, 0x3f, sizeof(f));
    f[0][2][3] = 0;
    tasks[0] = 1;
    for (int i = 0; i < N; i++) {
        for (int j = 1; j <= L; j++) {
            for (int k = 1; k <= L; k++) {
               int pos = tasks[i];
               if (pos == j || pos == k || j == k) continue;
                f[i + 1][j][k] = min(f[i + 1][j][k], f[i][j][k] + cost[pos][tasks[i + 1]]);
                f[i + 1][pos][k] = min(f[i + 1][pos][k], f[i][j][k] + cost[j][tasks[i + 1]]);
                f[i + 1][j][pos] = min(f[i + 1][j][pos], f[i][j][k] + cost[k][tasks[i + 1]]);
            }
        }
    }
    ans = 0x3f3f3f3f;
    for (int i = 1; i <= L; i++)
        for (int j = 1; j <= L; j++)
            ans = min(ans, f[N][i][j]);
    cout << ans << endl;
    return 0;
}