1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x51線性DP 移動服務

《演算法競賽進階指南》0x51線性DP 移動服務

題目連結: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; }