题目传送门
(f_{i,j,k})表示到第i次,一个人在j,一个人在k的最小花费.
因为其中一个人一定在(p_i)上.
(f_{i+1,j,k} = min) { (f_{i+1,j,k},f_{i,j,k}) } (+c_{p_i,p_{i+1}}) 第三人跳到本次指定的位置.
(f_{i+1,p_i,k} = min) { (f_{i+1,p_i,k},f_{i,j,k}) } (+c_{j,p_{i+1}}) 第一个人跳到本次指定的位置.
(f_{i+1,j,p_i} = min) { (f_{i+1,j,p_i},f_{i,j,k}) } (+c_{k,p_{i+1}}) 第二个人跳到本次指定的位置.
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long n,l,a[201][201],f[2][201][201],p[1001],q,ans = 2100000000;
inline long long mx() {
long long s = 0,w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') w = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
s = s * 10 + (ch - '0');
ch = getchar();
}
return s * w;
}
int main() {
l = mx();
n = mx();
memset(f,0x3f,sizeof(f));
for(int i = 1;i <= l; i++)
for(int j = 1;j <= l; j++)
a[i][j] = mx();
for(int i = 1;i <= n; i++)
p[i] = mx();
p[0] = 3;
f[0][1][2] = 0;
for(int i = 0;i < n; i++) {
q ^= 1;
for(int j = 1;j <= l; j++)
for(int k = 1;k <= l; k++) {
if(i == 0 && (j != 1 || k != 2)) continue;//初始位置时特殊处理
if(j != p[i+1] && k != p[i+1]) f[q][j][k] = min(f[q][j][k],f[q^1][j][k] + a[p[i]][p[i+1]]);
if(p[i] != k && p[i] != p[i+1]) f[q][p[i]][k] = min(f[q][p[i]][k],f[q^1][j][k] + a[j][p[i+1]]);
if(j != p[i] && p[i] != p[i+1]) f[q][j][p[i]] = min(f[q][j][p[i]],f[q^1][j][k] + a[k][p[i+1]]);
f[q^1][j][k] = 0x3f3f3f3f;//将初始位置初始化,便于更新答案
}
}
for(int i = 1;i <= l; i++)
for(int j = 1;j <= l; j++)
if(i != j) ans = min(ans,f[q][i][j]);
printf("%lld",ans);
return 0;
}