一个公司有三个移动服务员,最初分别在位置 1,2,3 处。
如果某个位置(用一个整数表示)有一个请求,那么公司必须指派某名员工赶到那个地方去。
某一时刻只有一个员工能移动,且不允许在同样的位置出现两个员工。
从 p 到 q 移动一个员工,需要花费 c(p,q)。
这个函数不一定对称,但保证 c(p,p)=0。
给出 N 个请求,请求发生的位置分别为 p1∼pN。
公司必须按顺序依次满足所有请求,且过程中不能去其他额外的位置,目标是最小化公司花费,请你帮忙计算这个最小花费。
第 1 行有两个整数 L,N,其中 L 是位置数量,N 是请求数量,每个位置从 1 到 L 编号。
第 2 至 L+1 行每行包含 L 个非负整数,第 i+1 行的第 j 个数表示 c(i,j),并且它小于 2000。
最后一行包含 N 个整数,是请求列表。
一开始三个服务员分别在位置 1,2,3。
输出一个整数 M,表示最小花费。
3≤L≤200
1≤N≤1000
- 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
5
用当前状态更新依赖他的状态
我首先想到的将集合划分为 f[i][j][k] 表示第一个服务员在位置 i ,第二个服务员在位置 j ,第三个服务员在位置 k,的最小花费;
这是一个不重不漏的子集,但这种划分方式没法写出状态转移方程;
所以我们必须想出另一种集合的划分方式:我们观察发现服务员所在的位置和询问的信息有关,上述的第一种划分方式我们甚至无法知道最终答案是哪个状态。
发现这一性质后,我们划分的状态就可以包含询问这一信息,至此我们就可以将状态划分
f[i][x][y][z] 表示:表示第 i 次询问后,有一个服务员在 x ,另一个服务员在 y ,还有一个在 z ,的最小花费。
这里我们可以优化一下,易知,在第 i 次访问完后,三个服务员中必有一个下位置 p[i] ,不妨让 z 表示最后更新的位置,这样我们就可以将4维压缩成为3维:
f[i][x][y] 表示 表示第 i 次询问后,有一个服务员在 x ,另一个服务员在 y ,还有一个在 z ,的最小花费。其中 z 就是 p[i] ,这里将其省略
状态转移:
我们发现 f[i][x][y] 的前一个状态有很多种,但它的下一种状态却只有三种,所以这里使用另一种状态转移方式:由当前的更新下一个状态,而非由前一个状态更新当前状态
f[i + 1][x][y] = min(f[i + 1][x][y], f[i][x][y] + w[z][u]);
f[i + 1][z][y] = min(f[i + 1][z][y], f[i][x][y] + w[x][u]);
f[i + 1][x][z] = min(f[i + 1][x][z], f[i][x][y] + w[y][u]);
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- using namespace std;
- typedef long long LL;
- const int N = 2e2 + 5, M = 1e3 + 5;
- int L, n;
- int p[M],w[N][N];
- int f[M][N][N];
-
- int main() {
- scanf("%d%d", &L, &n);
- for (int i = 1; i <= L; i++) {
- for (int j = 1; j <= L; j++) {
- scanf("%d", &w[i][j]);
- }
- }
- for (int i = 1; i <= n; i++) {
- scanf("%d", &p[i]);
- }
- p[0] = 3;
- memset(f, 0x3f3f3f3f, sizeof(f));
- f[0][1][2] = 0;
- for (int i = 0; i <= n; i++) {
- for (int x = 1; x <= L; x++) {
- for (int y = 1; y <= L; y++) {
- int z = p[i], u = p[i + 1];//第四维是最近一次配更新的位置
- if (x == y || y == z || z == x)continue;
- f[i + 1][x][y] = min(f[i + 1][x][y], f[i][x][y] + w[z][u]);
- f[i + 1][z][y] = min(f[i + 1][z][y], f[i][x][y] + w[x][u]);
- f[i + 1][x][z] = min(f[i + 1][x][z], f[i][x][y] + w[y][u]);
- }
- }
- }
- int ans = 0x3f3f3f3f,z=p[n];
- for (int x = 1; x <= L; x++) {
- for (int y = 1; y <= L; y++) {
-
- if (x == y || y == z || z == x)continue;
- ans = min(ans, f[n][x][y]);
- }
- }
- cout << ans << endl;
- return 0;
- }