我们可以表示w[i][j][k]为送完第i个件,且另外两个人的位置分别是j,k的最短路径,那么比较容易得到转移,我们可以手动枚举第i个邮件是哪个位置的人送的,更新该答案。
数组较大,我们可以滚动第一维。
/************************************************************** Problem: 1820 User: BLADEVIL Language: C++ Result: Accepted Time:1512 ms Memory:2216 kb ****************************************************************/ //By BLADEVIL #include <cstdio> #include <cstring> #define maxn 300 #define inf 1<<30 using namespace std; int n,ans; int dis[maxn][maxn],w[3][maxn][maxn],a[1010]; void getmin(int &x,int y) {x=(y>x)?x:y;} int main() { scanf("%d",&n); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) scanf("%d",&dis[i][j]); memset(w,40,sizeof w); w[0][2][3]=w[0][3][2]=0; a[0]=1; int q,p; p=q=1; while (scanf("%d",&a[q])!=EOF) { memset(w[p],40,sizeof w[p]); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { getmin(w[p][i][j],w[1-p][i][j]+dis[a[q-1]][a[q]]); getmin(w[p][a[q-1]][j],w[1-p][i][j]+dis[i][a[q]]); getmin(w[p][a[q-1]][i],w[1-p][i][j]+dis[j][a[q]]); } p=1-p; q++; } ans=inf; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) getmin(ans,w[1-p][i][j]); printf("%d ",ans); return 0; }