1. 程式人生 > >HDU 6166 Senior Pan(k點中最小兩點間距離)題解

HDU 6166 Senior Pan(k點中最小兩點間距離)題解

所有 bsp iostream 其中 ios -- ini pre prior

題意:n個點,m條有向邊,指定k個點,問你其中最近的兩點距離為多少

思路:這題的思路很巧妙,如果我們直接枚舉兩點做最短路那就要做C(k,2)次。但是我們換個思路,我們把k個點按照二進制每一位的0和1分類logn次,然後做集合最短距離。因為任意兩個不等的數,總有一位不一樣,所以每個點都有機會和其他點在不同集合。那麽這樣就花了logn次枚舉了所有情況。集合最短距離可以指定一個超級源點和超級匯點,然後做兩點最短路。

代碼:

#include<cmath>
#include<set>
#include<queue>
#include<cstdio>
#include
<vector> #include<cstring> #include <iostream> #include<algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 100000 + 10; const ull seed = 131; const int INF = 0x3f3f3f3f; const int MOD = 1000000007; struct Edge{ int to, w, next; }edge[maxn
* 2]; struct node{ int v, w; node(int _v = 0, int _w = 0): v(_v), w(_w){} bool operator < (const node r) const{ return w > r.w; } }; int head[maxn], tot; void addEdge(int u, int v, int w){ edge[tot].w = w; edge[tot].to = v; edge[tot].next = head[u]; head[u]
= tot++; } int n, m, k; int dis[maxn], q[maxn]; bool vis[maxn]; int dij(int s, int e){ memset(vis, false, sizeof(vis)); memset(dis, INF, sizeof(dis)); priority_queue<node> Q; while(!Q.empty()) Q.pop(); dis[s] = 0; Q.push(node(s, 0)); node tmp; while(!Q.empty()){ tmp = Q.top(); Q.pop(); int u = tmp.v; if(vis[u]) continue; vis[u] = true; for(int i = head[u]; i != -1; i = edge[i].next){ int v = edge[i].to; if(!vis[v] && dis[v] > dis[u] + edge[i].w){ dis[v] = dis[u] + edge[i].w; Q.push(node(v, dis[v])); } } } return dis[e]; } void init(){ memset(head, -1, sizeof(head)); tot = 0; } int a[maxn], b[maxn], w[maxn]; int main(){ int T, ca = 1; scanf("%d", &T); while(T--){ scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++){ scanf("%d%d%d", &a[i], &b[i], &w[i]); } scanf("%d", &k); for(int i = 1; i <= k; i++){ scanf("%d", &q[i]); } int ans = INF, p = 0; while(n >> p){ init(); for(int i = 1; i <= m; i++) addEdge(a[i], b[i], w[i]); for(int i = 1; i <= k; i++){ if((q[i] >> p) & 1){ addEdge(0, q[i], 0); } else{ addEdge(q[i], n + 1, 0); } } ans = min(ans, dij(0, n + 1)); init(); for(int i = 1; i <= m; i++) addEdge(a[i], b[i], w[i]); for(int i = 1; i <= k; i++){ if((q[i] >> p) & 1){ addEdge(q[i], 0, 0); } else{ addEdge(n + 1, q[i], 0); } } ans = min(ans, dij(n + 1, 0)); p++; } printf("Case #%d: %d\n", ca++, ans); } return 0; }

HDU 6166 Senior Pan(k點中最小兩點間距離)題解