UVa11813 Shopping

問題
http://uva.onlinejudge.org/external/118/11813.html

概要
無向グラフにおいて、グラフの接続情報とコストが与えられる。
全てのノードの内、店のノード番号が複数指定されるので、ノード0から出発して最小コストで全ての店を巡回せよ。

制約

  1. ノードとエッジの数はそれぞれ 100000 以下
  2. 店は10店舗以下。

解法
すべての店からダイクストラした後、TSPを解く。
高々11回(店舗数+はじめの位置)のダイクストラをすれば良い。

#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

#define MAX_V (100010)
#define INF ((int)1e9)

struct Edge {
  int to, cost;
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

Graph G;

int N, M, S;
int stores[11];
int d[11][MAX_V];

typedef pair<int, int> Pii; // cost, curr
void dijkstra(int sid) {
  
  fill(d[sid], d[sid]+MAX_V, INF);
  d[sid][stores[sid]] = 0;
  priority_queue<Pii, vector<Pii>, greater<Pii> > pq;
  pq.push(Pii(0, stores[sid]));
  while(!pq.empty()) {
    Pii top = pq.top(); pq.pop();
    int const curr = top.second;
    int const cost = top.first;
    for(int i=0; i<G[curr].size(); i++) {
      const Edge& e = G[curr][i];
      if(d[sid][e.to] > cost+e.cost) {
        d[sid][e.to] = cost+e.cost;
        pq.push(Pii(cost+e.cost, e.to));
      }
    }
  }
  
}

int dp[1<<11][11];
int main() {
  
  int Tc; cin >> Tc;
  while(Tc--) {
    cin >> N >> M;
    G.clear(); G.resize(N);
    for(int i=0; i<M; i++) {
      int x, y, c; cin >> x >> y >> c;
      G[x].push_back((Edge){y, c});
      G[y].push_back((Edge){x, c});
    }
    
    cin >> S; stores[0] = 0; S++;
    for(int i=1; i<S; i++) {
      int x; cin >> stores[i];
    }
    for(int i=0; i<S; i++)
      dijkstra(i);
    
    fill(dp[0], dp[0]+(1<<11)*11, INF);
    dp[1][0] = 0;
    for(int st=0; st<(1<<S); st++) {
      for(int u=0; u<S; u++) {
        if(!((st>>u)&1)) continue;
        for(int v=0; v<S; v++) {
          if((st>>v)&1) continue;
          if(dp[st|(1<<v)][v] > dp[st][u]+d[u][stores[v]]) {
            dp[st|(1<<v)][v] = dp[st][u]+d[u][stores[v]];
          }
        }
      }
    }
    
    int ans = INF;
    for(int i=1; i<S; i++) {
      ans = min(ans, dp[(1<<S)-1][i]+d[i][stores[0]]);
    }
    
    cout << ans << endl;
    
  }
  
  return 0;
}