易错点
- 滚动数组的技巧:dp[i&1]=dp[(i-1)&1]+1.
- 直接dp(dp[i][x][y][z])的话复杂度开不下,可以考虑减少一维.
- 容易发现对于每一个任务,在这个任务被执行之前一定有一个人在上一个任务的位置.
- 因此可以枚举上一个任务其中两个人所在的位置,那么另一个人一定在上一个任务所要求的位置.
- 注意需要特判某个位置已经有人的情况.
- 滚动数组需要及时清空不需要的位置信息。可以发现每个x、y仅会使用一次,那么使用后直接清空上一个任务的信息即可.
(dp[(i-1)&1][x][y]=INF)
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int INF=0x3f3f3f3f;
int dp[2][210][210],c[210][210],p[1010];
int main(){
int l,n;
scanf("%d%d",&l,&n);
for(int i=1;i<=l;i++)
for(int j=1;j<=l;j++)
scanf("%d",&c[i][j]);
for(int i=1;i<=n;i++)
scanf("%d",&p[i]);
memset(dp,0x3f,sizeof(dp));
dp[0][1][2]=0;
p[0]=3;
for(int i=1;i<=n;i++)
for(int x=1;x<=l;x++)
for(int y=1;y<=l;y++){
if(dp[(i-1)&1][x][y]==INF)continue;
int z=p[i-1];
if(y!=p[i]&&z!=p[i])dp[i&1][y][z]=min(dp[i&1][y][z],dp[(i-1)&1][x][y]+c[x][p[i]]);
if(x!=p[i]&&z!=p[i])dp[i&1][x][z]=min(dp[i&1][x][z],dp[(i-1)&1][x][y]+c[y][p[i]]);
if(x!=p[i]&&y!=p[i])dp[i&1][x][y]=min(dp[i&1][x][y],dp[(i-1)&1][x][y]+c[z][p[i]]);
dp[(i-1)&1][x][y]=INF;
}
int ans=INF;
for(int x=1;x<=l;x++)
for(int y=1;y<=l;y++)
ans=min(ans,dp[n&1][x][y]);
printf("%d\n",ans);
return 0;
}