原题链接:洛谷P5304 [GXOI/GZOI2019]旅行者
题解
题意:在一个无向图中指定k个点,求这k个点中两两最短路长度的最小值
算法:dijkstra+合并点+二进制
1.暴力
对于每一个指定点,跑k次dijkstra,暴力比较最小值,复杂度O(N2logM)。
for(int i=1;i<=K;i++){ dijkstra(spe[i]); for(int j=1;j<=K;j++) if(j!=i&&dis[spe[j]]<ans) ans=dis[spe[j]]; }
完整代码,50opt:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int MAXN = 1e5 + 7, MAXM = 1e6 + 50; 5 const LL INF = 1e17 + 7; 6 int head[MAXN], sz, nxt[MAXM], len[MAXM], to[MAXM]; 7 inline void add(int x, int y, LL z) { 8 nxt[++sz] = head[x]; 9 head[x] = sz; 10 to[sz] = y; 11 len[sz] = z; 12 nxt[++sz] = head[y]; 13 head[y] = sz; 14 to[sz] = y; 15 len[sz] = z; 16 } 17 LL dis[MAXN], ans; 18 int spe[MAXN] /*special point*/, is[MAXN] /*is special*/; 19 bool vis[MAXN]; 20 inline void dijkstra(int S) { 21 memset(dis, 0x3f, sizeof(dis)); 22 memset(vis, 0, sizeof(vis)); 23 priority_queue<pair<LL, int>, vector<pair<int, int> >, greater<pair<int, int> > > pq; 24 pq.push(make_pair(0, S)); 25 while (pq.size()) { 26 pair<LL, int> cur = pq.top(); 27 pq.pop(); 28 int idx = cur.second; 29 LL dist = cur.first; 30 if (vis[idx] || dis[idx] < dist) 31 continue; 32 vis[idx] = 1; 33 for (int i = head[idx]; i; i = nxt[i]) 34 if (!vis[to[i]] && dist + len[i] < dis[to[i]]) { 35 dis[to[i]] = dist + len[i]; 36 pq.push(make_pair(dis[to[i]], to[i])); 37 } 38 } 39 } 40 int Case, N, M, K; 41 int main() { 42 scanf("%d", &Case); 43 while (Case--) { 44 scanf("%d%d%d", &N, &M, &K); 45 sz = 0; 46 memset(head, 0, sizeof(head)); 47 for (int i = 1; i <= M; i++) { 48 int ii, jj; 49 LL kk; 50 scanf("%d%d%lld", &ii, &jj, &kk); 51 add(ii, jj, kk); 52 } 53 memset(is, 0, sizeof(is)); 54 for (int i = 1; i <= K; i++) { 55 scanf("%d", spe + i); 56 is[spe[i]] = 1; 57 } 58 ans = INF; 59 for (int i = 1; i <= K; i++) { 60 dijkstra(spe[i]); 61 for (int j = 1; j <= K; j++) 62 if (j != i && dis[spe[j]] < ans) 63 ans = dis[spe[j]]; 64 } 65 printf("%lld\n", ans); 66 } 67 return 0; 68 }