UVA 10816 Travel in Desert ( 最小瓶頸生成樹 + 最短路徑 / 二分 + 最短路徑 )
UVa Online Judge
可以先依據邊的溫度求最小瓶頸生成樹,但這裡生成的條件是起點和終點為同一個連通分量即可。求出最小溫度後對這些邊求起點至終點的最短路徑就行了。無聊寫了SPFA跟Dijkstra,運行時間一模一樣。
#include <bits/stdc++.h> using namespace std; const int MAXN = 100 + 2; const int MAXM = 1e4 + 4; const double INF = 1e10; struct UnionFind{ int fa[MAXN]; void init(int n){ for(int i = 0; i <= n; ++i) fa[ i ] = i; } int find(int x){ return fa[x] == x ? x : fa[x] = find( fa[x] ); } bool same(int a, int b){ int x = find( a ), y = find( b ); return x == y; } bool unite(int a, int b){ int x = find( a ), y = find( b ); if( x == y ) return false; fa[ x ] = y; return true; } } uf; struct Edge{ int u, v; double hot, dis; Edge(){} Edge(int _u, int _v, double _h, double _d): u(_u), v(_v), hot(_h), dis(_d){} } es[MAXM]; bool cmpHot(const Edge &a, const Edge &b){ return a.hot < b.hot; } int n, m; int src, gol; vector<Edge> G[MAXN]; struct Kruskal{ void init(){ uf.init( n ); sort( es, es + m, cmpHot ); } double solve(){ double res; for(int i = 0; i < m; ++i) if( uf.unite( es[i].u, es[i].v ) ){ res = es[i].hot; if( uf.same( src, gol ) ) break; } assert( uf.same( src, gol ) ); return res; } } mst; /* struct Dijkstra{ double dis[MAXN]; int vis[MAXN], pre[MAXN]; void init(){ fill( dis, dis + MAXN, INF ); memset( vis, 0, sizeof(vis) ); memset( pre, -1, sizeof(pre) ); } void printPath(){ stack<int> route; int u = gol; while( u != -1 ) route.push( u ), u = pre[ u ]; for( ; !route.empty(); route.pop()) printf("%d%c", route.top(), route.size() == 1 ? '\n' : ' '); } typedef pair<double, int> pdi; void solve(double mh){ // can only pass edges that are not hotter than mh priority_queue<pdi, vector<pdi>, greater<pdi> > pq; pq.push( pdi( dis[ src ] = 0.0, src ) ); while( !pq.empty() ){ int u = pq.top().second; pq.pop(); if( vis[ u ] ) continue; vis[ u ] = 1; if( u == gol ) return; for(int i = 0; i < G[u].size(); ++i){ int v = G[u][i].v; if( G[u][i].hot > mh ) continue; if( dis[ v ] > dis[ u ] + G[u][i].dis ){ dis[ v ] = dis[ u ] + G[u][i].dis; pre[ v ] = u; pq.push( pdi( dis[ v ], v ) ); } } } } } sp; */ struct SPFA{ double dis[MAXN]; int pre[MAXN], inq[MAXN]; void init(){ fill( dis, dis + MAXN, INF ); memset( pre, -1, sizeof(pre) ); memset( inq, 0, sizeof(inq) ); } void printPath(){ stack<int> route; int u = gol; while( u != -1 ) route.push( u ), u = pre[ u ]; for( ; !route.empty(); route.pop()) printf("%d%c", route.top(), route.size() == 1 ? '\n' : ' '); } void solve(double mh){ queue<int> que; que.push( src ); dis[ src ] = 0; while( !que.empty() ){ int u = que.front(); que.pop(); inq[ u ] = 0; for(int i = 0; i < G[u].size(); ++i){ int v = G[u][i].v; if( G[u][i].hot > mh ) continue; if( dis[ v ] > dis[ u ] + G[u][i].dis ){ dis[ v ] = dis[ u ] + G[u][i].dis; pre[ v ] = u; if( !inq[ v ] ) que.push( v ); } } } } } spfa; void solve(){ mst.init(); double max_hot = mst.solve(); // max hot of min - hot - spanning tree spfa.init(); spfa.solve( max_hot ); spfa.printPath(); printf("%.1lf %.1lf\n", spfa.dis[ gol ], max_hot); } void init(){ for(int i = 0; i <= n; ++i) G[i].clear(); } int main(){ while( scanf("%d%d", &n, &m) == 2 ){ init(); scanf("%d%d", &src, &gol); for(int i = 0; i < m; ++i){ int u, v; double h, d; scanf("%d%d%lf%lf", &u, &v, &h, &d); es[ i ] = Edge( u, v, h, d ); G[ u ].push_back( Edge( u, v, h, d ) ); G[ v ].push_back( Edge( v, u, h, d ) ); } solve(); } return 0; }
另外還可以二分枚舉一個熱度值,求兩端點距離,檢查是否可以達到。或許有輕鬆一點點。
#include <bits/stdc++.h> using namespace std; const int MAXN = 100 + 2; const int MAXM = 1e4 + 4; const double INF = 1e10; struct Edge{ int u, v; double hot, dis; Edge(){} Edge(int _u, int _v, double _h, double _d): u(_u), v(_v), hot(_h), dis(_d){} } es[MAXM]; bool cmpHot(const Edge &a, const Edge &b){ return a.hot < b.hot; } int n, m; int src, gol; vector<Edge> G[MAXN]; struct SPFA{ double dis[MAXN]; int pre[MAXN], inq[MAXN]; void init(){ fill( dis, dis + MAXN, INF ); memset( pre, -1, sizeof(pre) ); memset( inq, 0, sizeof(inq) ); } void printPath(){ stack<int> route; int u = gol; while( u != -1 ) route.push( u ), u = pre[ u ]; for( ; !route.empty(); route.pop()) printf("%d%c", route.top(), route.size() == 1 ? '\n' : ' '); } bool ok(double mh){ // cannot pass edge hot > mh queue<int> que; que.push( src ); dis[ src ] = 0.0; while( !que.empty() ){ int u = que.front(); que.pop(); inq[ u ] = 0; if( u == gol ) return true; for(int i = 0; i < G[u].size(); ++i){ int v = G[u][i].v; if( G[u][i].hot > mh ) continue; if( dis[ v ] > dis[ u ] + G[u][i].dis ){ dis[ v ] = dis[ u ] + G[u][i].dis; pre[ v ] = u; if( !inq[ v ] ) que.push( v ), inq[ v ] = 1; } } } return false; } } sp; void solve(){ double lb = 0.0, rb = 50.0; while( rb - lb > 1e-3 ){ double mid = ( lb + rb ) / 2.0; sp.init(); if( sp.ok( mid ) ) rb = mid; else lb = mid; } sp.init(); assert( sp.ok( rb ) ); // make sure the path is ok sp.printPath(); printf("%.1lf %.1lf\n", sp.dis[ gol ], rb); } void init(){ for(int i = 0; i <= n; ++i) G[i].clear(); } int main(){ while( scanf("%d%d%d%d", &n, &m, &src, &gol) == 4 ){ init(); for(int i = 0; i < m; ++i){ int u, v; double h, d; scanf("%d%d%lf%lf", &u, &v, &h, &d); es[i] = Edge( u, v, h, d ); G[ u ].push_back( es[i] ); G[ v ].push_back( Edge( v, u, h, d ) ); } solve(); } return 0; }