解题思路
在第一反应下,我们不难想出以下状态:
f
[
i
]
[
x
]
[
y
]
[
z
]
f [ i ] [ x ] [ y ] [ z ]
f[i][x][y][z] 表 示 完 成 了 前 i 个 请 求 , 三 个 员 工 分 别 位 于
x
,
y
,
z
x , y , z
x,y,z位 置 的 最 小 花 费
f
[
i
]
[
x
]
[
y
]
[
z
]
f[i][x][y][z]
f[i][x][y][z] 表示完成了前i个请求,三个员工分别位于
x
,
y
,
z
x,y,z
x,y,z 位置的最小花费
f
[
i
]
[
x
]
[
y
]
[
z
]
f[i][x][y][z]
f[i][x][y][z]表示完成了前i个请求,三个员工分别位于x,y,z位置的最小花费
我们可以考虑 用 阶段 i-1 来更新当前状态。
那么方程十分显然 ,这里不再说。
考虑优化
由于我们可以确定在进行第i个任务时,第i-1个任务已经完成,也就是说肯定有一个人在p[i-1]这个位置上,根据这个特性,我们可以优化空间:
设
f
[
i
]
[
x
]
[
y
]
f [ i ] [ x ] [ y ]
f[i][x][y] 表 示 完 成 了 前 i 个 请 求 , 其 他 两 个 员 工 位 于 x , y 位 置 的 最 小 花 费 f[i][x][y] 表示完成了前i个请求,其他两个员工位于 x,y 位置的最小花费f[i][x][y]表示完成了前i个请求,其他两个员工位于
x
,
y
x,y
x,y位置的最小花费
根据第三个人的位置是 p [ i − 1 ] p[i-1] p[i−1],我们可以列出一下方程:
- f [ o k ] [ j ] [ k ] = f [ o k ] [ k ] [ j ] = m i n ( f [ o k ] [ j ] [ k ] , f [ o k 1 ] [ j ] [ k ] + a [ p [ i − 1 ] ] [ p [ i ] ] ) ; f[ok][j][k]=f[ok][k][j]=min(f[ok][j][k],f[ok^1][j][k]+a[p[i-1]][p[i]]); f[ok][j][k]=f[ok][k][j]=min(f[ok][j][k],f[ok1][j][k]+a[p[i−1]][p[i]]);
- f [ o k ] [ p [ i − 1 ] ] [ k ] = f [ o k ] [ k ] [ p [ i − 1 ] ] = m i n ( f [ o k ] [ k ] [ p [ i − 1 ] ] , f [ o k 1 ] [ j ] [ k ] + a [ j ] [ p [ i ] ] ) ; f[ok][p[i-1]][k]=f[ok][k][p[i-1]]=min(f[ok][k][p[i-1]],f[ok^1][j][k]+a[j][p[i]]); f[ok][p[i−1]][k]=f[ok][k][p[i−1]]=min(f[ok][k][p[i−1]],f[ok1][j][k]+a[j][p[i]]);
- f [ o k ] [ p [ i − 1 ] ] [ j ] = f [ o k ] [ j ] [ p [ i − 1 ] ] = m i n ( f [ o k ] [ j ] [ p [ i − 1 ] ] , f [ o k 1 ] [ j ] [ k ] + a [ k ] [ p [ i ] ] ) ; f[ok][p[i-1]][j]=f[ok][j][p[i-1]]=min(f[ok][j][p[i-1]],f[ok^1][j][k]+a[k][p[i]]); f[ok][p[i−1]][j]=f[ok][j][p[i−1]]=min(f[ok][j][p[i−1]],f[ok1][j][k]+a[k][p[i]]);
考虑到数组范围会MLE,开个滚动数组就好了
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#define ll long long
#define ldb long double
using namespace std;
int l,n,ans,a[210][210],p[1010],f[2][210][210];
bool ok;
int main(){
scanf("%d%d",&l,&n);
for(int i=1;i<=l;i++)
for(int j=1;j<=l;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
memset(f,127,sizeof(f));
p[0]=3;
f[0][1][2]=0;
ans=1e9;
ok=0;
for(int i=1;i<=n;i++)
{
ok=ok^1;
for(int j=1;j<=l;j++)
{
for(int k=1;k<=l;k++)
{
if(p[i-1]==j||p[i-1]==k||j==k)continue;
f[ok][j][k]=f[ok][k][j]=min(f[ok][j][k],f[ok^1][j][k]+a[p[i-1]][p[i]]);
f[ok][p[i-1]][k]=f[ok][k][p[i-1]]=min(f[ok][k][p[i-1]],f[ok^1][j][k]+a[j][p[i]]);
f[ok][p[i-1]][j]=f[ok][j][p[i-1]]=min(f[ok][j][p[i-1]],f[ok^1][j][k]+a[k][p[i]]);
if(i==n)
ans=min(ans,min(f[ok][j][k],min(f[ok][p[i-1]][j],f[ok][p[i-1]][k])));
}
}
memset(f[ok^1],127,sizeof(f[ok^1]));
}
printf("%d",ans);
}
/*
4 10
0 5 0 8
8 0 5 6
1 8 0 6
1 1 4 0
1 1 1 1 4 4 2 2 2 3
*/