藍書(演算法競賽進階指南)刷題記錄——Mobile Service
阿新 • • 發佈:2018-12-12
題目大意:三個人一開始在1,2,3的位置,每次給定一個1~l的座標(必須按順序),他們之中必須有一個人走到這個座標,且他們之中不能有兩人站在同一位置,從點x走到點y的花費為c(x,y),求最小花費.
首先這是一道十分裸的DP,我們可以設狀態f[i][x][y][z]為走過前i個給定座標,且當前第一個人在位置x,第二個人在位置y,第三個人在位置z的最小花費.
考慮三個人的走法,設第i個座標為go[i],我們可以很容易推出方程:
這個演算法的時空複雜度為,TLE+MLE.
我們發現,當一個狀態f[i]是有意義的情況下,必定有一個人的位置為go[i].而直到三個人的座標不需要知道順序,所以我們的狀態可以簡化成f[i][x][y]表示走過前i個給定座標,有一個人的座標為x,有一個人的座標為y,有一個人的座標為go[i]即可.
那麼我們設go[0]為3,然後初始化f[0][1][2]=f[0][2][1]=0.
方程如同上面,分別推斷三個情況可以得出:
那麼這道題其實就這樣可以AC了,時間複雜度,空間複雜度若加上滾動陣列可以進一步優化空間複雜度為.
程式碼如下:
#include<bits/stdc++.h> using namespace std; #define Abigail inline void const int L=200,N=1000; const int INF=(1<<30)-1; int l,dis[L+9][L+9]; int n,go[N+9]; int ans,f[N+9][L+9][L+9]; void getmin(int &a,int b){ a=a<b?a:b; } Abigail into(){ scanf("%d%d",&l,&n); for (int i=1;i<=l;i++) for (int j=1;j<=l;j++) scanf("%d",&dis[i][j]); for (int i=1;i<=n;i++) scanf("%d",&go[i]); } Abigail work(){ for (int i=0;i<=N+1;i++) for (int j=0;j<=L+1;j++) for (int k=0;k<=L+1;k++) f[i][j][k]=INF; int x,y; go[0]=3; f[0][1][2]=0;f[0][2][1]=0; for (int i=0;i<n;i++) for (int j=1;j<=l;j++) for (int k=1;k<=l;k++){ x=go[i];y=go[i+1]; if (j^y&&k^y&&j^k) getmin(f[i+1][j][k],f[i][j][k]+dis[x][y]); if (x^y&&k^y&&x^k) getmin(f[i+1][x][k],f[i][j][k]+dis[j][y]); if (x^y&&j^y&&x^j) getmin(f[i+1][j][x],f[i][j][k]+dis[k][y]); } ans=INF; for (int i=1;i<=l;i++) for (int j=1;j<=l;j++) getmin(ans,f[n][i][j]); } Abigail outo(){ printf("%d\n",ans); } int main(){ into(); work(); outo(); return 0; }