結果
| 問題 |
No.114 遠い未来
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2014-12-29 03:20:46 |
| 言語 | C++11(廃止可能性あり) (gcc 13.3.0) |
| 結果 |
AC
|
| 実行時間 | 1,927 ms / 5,000 ms |
| コード長 | 3,254 bytes |
| コンパイル時間 | 2,099 ms |
| コンパイル使用メモリ | 174,924 KB |
| 実行使用メモリ | 9,088 KB |
| 最終ジャッジ日時 | 2024-06-13 00:51:23 |
| 合計ジャッジ時間 | 12,372 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 3 |
| other | AC * 25 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<int> VI;
typedef vector<VI> VVI;
#define REP(i, n) for(int(i)=0;(i)<(n);++(i))
int N, M, T;
const int INF = 1<<28;
// ref: http://www.prefield.com/algorithm/dp/steiner_tree.html
template<typename _Tw>
_Tw minimum_steiner_tree(const vector<int> &T, const vector<vector<_Tw> > &g) {
const int n = g.size(), nt = T.size();
if(nt <= 1) return 0;
vector<vector<_Tw> > d(g); // all-pair shortest
for(int k = 0; k < n; ++k)
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
vector<vector<_Tw> > OPT(1<<nt, vector<_Tw>(n));
for(int S = 0; S < (1 << nt); ++S)
for(int x = 0; x < n; ++x)
OPT[S][x] = INF;
for(int p = 0; p < nt; ++p) // trivial case
for(int q = 0; q < n; ++q)
OPT[1 << p][q] = d[T[p]][q];
for(int S = 1; S < (1 << nt); ++S) { // DP step
if(!(S & (S-1))) continue;
for(int p = 0; p < n; ++p)
for(int E = (S-1)&S; E ; E = (E-1)&S)
OPT[S][p] = min(OPT[S][p], OPT[E][p] + OPT[S-E][p]);
for(int p = 0; p < n; ++p)
for(int q = 0; q < n; ++q)
OPT[S][p] = min(OPT[S][p], OPT[S][q] + d[p][q]);
}
_Tw ans = INF;
for(int S = 0; S < (1 << nt); ++S)
for(int q = 0; q < n; ++q)
ans = min(ans, OPT[S][q] + OPT[((1 << nt)-1)-S][q]);
return ans;
}
class uf_ {
public:
vector<int> node;
uf_(int n) : node(n, -1){;}
void con(int n, int m){
n = root(n); m = root(m); if(n == m) return;
node[n] += node[m]; node[m] = n;
}
bool is_con(int n, int m){ return root(n) == root(m); }
int root(int n){ return (node[n] < 0) ? n : node[n] = root(node[n]); }
int size(int n){ return -node[root(n)]; }
};
int main(){
cin >> N >> M >> T;
VVI g(N,VI(N,INF));
REP(i,N) g[i][i] = 0;
vector<pair<int,pair<int,int> > > e;
REP(i,M){
int a,b,c;
cin >> a >> b >> c; a--,b--;
g[a][b] = g[b][a] = c;
e.push_back(make_pair(c, make_pair(a,b)));
}
ll mask = 0;
VI t(T);
REP(i,T){
int tt; cin >> tt; tt--;
t[i] = tt;
mask |= 1LL<<tt;
}
mask ^= (1LL<<N) - 1;
int res = 1<<29;
if(T < 16){
res = minimum_steiner_tree<int>(t, g);
} else {
sort(e.begin(), e.end());
for(ll i = mask; i >= 0; i--){ // 使用しない頂点番号のビットサブセット列挙
i &= mask;
// kruskal
int cost = 0;
uf_ uf(N);
for(auto it = e.begin(); it != e.end(); ++it){
int c = it->first, u = it->second.first, v = it->second.second;
if(i & (1LL<<u) || i & (1LL<<v)) continue;
if(!uf.is_con(u,v)){
uf.con(u,v); cost += c;
}
}
// すべての重要点が連結されてるか
bool f = true;
REP(i,T){
if(!uf.is_con(t[0], t[i])){ f = false; break; }
}
if(f) res = min(res, cost);
}
}
cout << res << endl;
}