F. The Shortest Statement
http://codeforces.com/contest/1051/problem/F
题意:
n个点,m条边的无向图,每次询问两点之间的最短路。(m-n<=20)
分析:
dijkstra。
如果是一棵树,那么可以直接通过,dis[u]+dis[v]-dis[lca]*2来求。现在如果建出一棵树,那么非树边只有小于等于21条。
只经过树边的路径用上面的方式求出,考虑经过非树边的路径。
经过非树边(至少一条),那么一定经过了这条边的顶点,所以可以对顶点做一次最短路,如果询问u,v经过这个顶点,那么就是dis[u]+dis[v]。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 #define fi(s) freopen(s,"r",stdin); 12 #define fo(s) freopen(s,"w",stdout); 13 using namespace std; 14 typedef long long LL; 15 16 inline int read() { 17 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 18 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 19 } 20 21 const LL INF = 1e18; 22 const int N = 100005; 23 24 int head[N], nxt[N << 1], to[N << 1], len[N << 1], En; 25 int f[N][21], deth[N], tmp[100], tot; 26 LL dis[N], d[50][N]; 27 int n, m; 28 bool vis[N]; 29 30 void add_edge(int u,int v,int w) { 31 ++En, to[En] = v, len[En] = w, nxt[En] = head[u], head[u] = En; 32 ++En, to[En] = u, len[En] = w, nxt[En] = head[v], head[v] = En; 33 } 34 35 #define pa pair<LL,int> 36 #define mp(a,b) make_pair(a,b) 37 priority_queue< pa, vector< pa >, greater< pa > > q; 38 39 void Dijkstra(int id,int S) { 40 for (int i=1; i<=n; ++i) dis[i] = INF, vis[i] = false; 41 dis[S] = 0; 42 q.push(mp(0, S)); 43 while (!q.empty()) { 44 int u = q.top().second; q.pop(); 45 if (vis[u]) continue; 46 vis[u] = true; 47 for (int i=head[u]; i; i=nxt[i]) { 48 int v = to[i]; 49 if (dis[v] > dis[u] + len[i]) { 50 dis[v] = dis[u] + len[i]; 51 q.push(mp(dis[v], v)); 52 } 53 } 54 } 55 for (int i=1; i<=n; ++i) d[id][i] = dis[i]; 56 } 57 void dfs(int u,int fa) { 58 vis[u] = true; 59 f[u][0] = fa; 60 deth[u] = deth[fa] + 1; 61 for (int i=head[u]; i; i=nxt[i]) { 62 int v = to[i]; 63 if (v == fa) continue; 64 if (vis[v]) tmp[++tot] = u, tmp[++tot] = v; 65 else dis[v] = dis[u] + len[i], dfs(v, u); 66 } 67 } 68 int LCA(int u,int v) { 69 if (deth[u] < deth[v]) swap(u, v); 70 int d = deth[u] - deth[v]; 71 for (int i=20; i>=0; --i) 72 if (d & (1 << i)) u = f[u][i]; 73 if (u == v) return u; 74 for (int i=20; i>=0; --i) 75 if (f[u][i] != f[v][i]) 76 u = f[u][i], v = f[v][i]; 77 return f[u][0]; 78 } 79 int main() { 80 n = read(), m = read(); 81 for (int i=1; i<=m; ++i) { 82 int u = read(), v = read(), w = read(); 83 add_edge(u, v, w); 84 } 85 86 dfs(1, 0); 87 for (int i=1; i<=n; ++i) d[0][i] = dis[i]; 88 for (int j=1; j<=20; ++j) 89 for (int i=1; i<=n; ++i) f[i][j] = f[f[i][j-1]][j-1]; 90 sort(tmp + 1, tmp + tot + 1); 91 int lim = tot; tot = 1; 92 for (int i=2; i<=lim; ++i) if (tmp[tot] != tmp[i]) tmp[++tot] = tmp[i]; 93 for (int i=1; i<=tot; ++i) Dijkstra(i, tmp[i]); 94 95 int Q = read(); 96 while (Q --) { 97 int u = read(), v = read(); 98 int t = LCA(u, v); 99 LL ans = d[0][u] + d[0][v] - 2 * d[0][t]; 100 for (int i=1; i<=tot; ++i) 101 ans = min(ans, d[i][u] + d[i][v]); 102 printf("%I64d ",ans); 103 } 104 return 0; 105 }