Please sign in first.
公式
E - 配送計画 / Delivery Plan 解説
by
E - 配送計画 / Delivery Plan 解説
by
physics0523
印刷ページ
本問題は以下の \(2\) つの問題を組み合わせることで解くことができます。
便宜上、 \(C_{K+1}=1,C_{K+2}=N\) であるとします。
前者について、ダイクストラ法で以下の配列を作成します。
- \(d_{i,j} = C_i\) から \(C_j\) まで到達する最短経路の長さ
後者について、巡回セールスマン問題を以下の bitDP の形で解きます。
- \(dp[S][v] = \{\) 既に訪問した頂点の集合が \(S\) で、現在いる頂点が \(v\) である場合の最小の移動距離 \(\}\)
bitDP を \(1\) からの距離で初期化し、 bitDP の結果に \(N\) までの距離を適切に足すことで \(K\) 要素で bitDP が行えます。
全体として、時間計算量 \(O(K(N+M) \log N + 2^KK^2)\) で本問題に正解できます。
実装例 (C++):
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
using pl=pair<ll,ll>;
using Graph=vector<vector<pl>>;
vector<ll> dijkstra(ll v,Graph &g){
ll n=g.size();
vector<ll> d(n,4e18);
priority_queue<pl,vector<pl>,greater<pl>> pq;
d[v]=0;
pq.push({d[v],v});
while(!pq.empty()){
auto [cd,v]=pq.top(); pq.pop();
if(d[v]!=cd){continue;}
for(auto [nv,w] : g[v]){
if(d[nv]>d[v]+w){
d[nv]=d[v]+w;
pq.push({d[nv],nv});
}
}
}
return d;
}
int main(){
ll N,M,K;
cin >> N >> M >> K;
Graph g(N);
for(ll i=0;i<M;i++){
ll u,v,w;
cin >> u >> v >> w;
u--; v--;
g[u].push_back({v,w});
g[v].push_back({u,w});
}
vector<ll> C(K);
for(ll i=0;i<K;i++){
cin >> C[i];
C[i]--;
}
C.push_back(0);
C.push_back(N-1);
vector<vector<ll>> sg(K+2,vector<ll>(K+2));
for(ll i=0;i<K+2;i++){
auto d=dijkstra(C[i],g);
for(ll j=0;j<K+2;j++){
sg[i][j]=d[C[j]];
}
}
vector<vector<ll>> dp(1ll<<K,vector<ll>(K,4e18));
for(ll i=0;i<K;i++){
dp[(1ll<<i)][i]=sg[K][i];
}
ll res=4e18;
for(ll i=0;i<(1ll<<K);i++){
for(ll j=0;j<K;j++){
if(dp[i][j]>2e18){continue;}
for(ll k=0;k<K;k++){
if(i&(1ll<<k)){continue;}
dp[i|(1ll<<k)][k]=min(dp[i|(1ll<<k)][k],dp[i][j]+sg[j][k]);
}
}
}
for(ll i=0;i<K;i++){
res=min(res,dp[(1ll<<K)-1][i]+sg[i][K+1]);
}
cout << res << "\n";
return 0;
}
投稿日時:
最終更新:
