题目链接:https://www.acwing.com/problem/content/276/
题目给出m个地点,n个任务,每两个地点之间有距离,有三个服务员,初始时刻服务员在1,2,3位置,每个服务必须且只有一个人到指定的地点,问完成这些服务的最小移动距离之和,决策集合是所有完成了i个任务并且另外两个人在x,y位置的方案,属性是距离之和的最小值,在DP中有两种常见的更新方式,分别是通过依赖的状态来更新当前的状态和通过当前的状态去更新以来的状态
本问题中,任务完成之后就会有一个人在任务i指定的地点,自由度变为3,用当前状态去更新依赖的状态的话只有三条出边,容易更新。从(x,y,p[i])点移动的话,只会是x,y,z三个人中的一个进行了移动。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1010; const int maxm = 210; int p[maxn]; int w[maxm][maxm]; int f[maxn][maxm][maxm]; int n,m; int main(){ cin>>m>>n; for(int i=1;i<=m;i++) for(int j=1;j<=m;j++) scanf("%d",&w[i][j]); for(int i=1;i<=n;i++)scanf("%d",&p[i]); memset(f,0x3f,sizeof(f)); p[0]=3; f[0][1][2]=0; for(int i=0;i<n;i++){ for(int x=1;x<=m;x++){ for(int y=1;y<=m;y++){ int z=p[i],v=p[i+1]; if(x==y || y==z || x==z)continue; f[i+1][x][y]=min(f[i+1][x][y],f[i][x][y]+w[z][v]); f[i+1][y][z]=min(f[i+1][y][z],f[i][x][y]+w[x][v]); f[i+1][x][z]=min(f[i+1][x][z],f[i][x][y]+w[y][v]); } } } int ans = 0x3f3f3f3f; for(int x=1;x<=m;x++) for(int y=1;y<=m;y++){ int z=p[n]; if(x==y || x==z || y==z)continue; ans=min(ans,f[n][x][y]); } cout<<ans<<endl; }