Official

E - 配送ルートの最適化 / Optimization of Delivery Routes Editorial by physics0523


この問題は、典型的な 巡回セールスマン問題(TSP) の一例です。

巡回セールスマン問題は NP 困難 であるため多項式時間で解くことは困難ですが、時間計算量 \(O(2^NN^2)\) で解く方法があります。

bitDP を用いてこの問題を解くことができます。
bitDP の解説は以下の記事を参照できるほか、インターネット上に多くの解説が存在します。

bitDP を行う際、予め距離行列 ( つまり、 \(d_{i,j} = \) \(i\) から \(j\) に直接移動する際の距離 ) を求めておくと高速化できる場合があります。

なお、本問題では (地点の添え字を \(0\) 始まりにするものとして) \(dp[2^k][k] = d_{0,k}\) と初期化した上で、 \(dp[2^N-1][0]\) を答えとするとスマートに実装できます。
このようにすることで、 \(0\) から地点 \(k\) に移動するのにかかるコストで初期化され、 \(k\) から始めて全ての地点を \(1\) 度ずつ通った時に最後に地点 \(0\) を通る場合を抽出することができます。これは、 \(0\) から始めて全頂点を回って \(0\) に戻るサイクルに対応します。

時間計算量は \(O(2^NN^2)\) です。

実装例 (C++):

#include<bits/stdc++.h>

using namespace std;

int main(){
  int N;
  cin >> N;
  vector<int> X(N),Y(N);
  for(int i=0;i<N;i++){
    cin >> X[i] >> Y[i];
  }
  vector<vector<int>> d(N,vector<int>(N,1e9));
  for(int i=0;i<N;i++){
    for(int j=0;j<N;j++){
      d[i][j]=(X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j]);
    }
  }
  vector<vector<int>> dp(1<<N,vector<int>(N,1e9));
  for(int i=1;i<N;i++){
    dp[(1<<i)][i]=d[0][i];
  }
  for(int i=0;i<(1<<N);i++){
    for(int j=0;j<N;j++){
      if(dp[i][j]>5e8){continue;}
      for(int k=0;k<N;k++){
        if(i&(1<<k)){continue;}
        dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+d[j][k]);
      }
    }
  }
  cout << dp[(1<<N)-1][0] << "\n";
  return 0;
}

posted:
last update: