Amber <<Play with Trees Solutions>> 半径
只需计算这些相邻点Li,即为最优值了
在这之前,需要去除掉一些点,只保留最外层的那些,才能有上面那样子交点
/**//* n<=200 , m<= 20000的无向图 求一棵生成树,使得任意两点路径中的最大值最小
这题就是求最小直径生成树了MSDT 有Kariv-Hakimi 算法
Amber的Play with Trees Solutions有这道题比较具体的解答 “最短路徑樹不見得是最小直徑生成樹” absoulte center是边上的一个点(不仅仅是图的顶点),它也是最短最长路径的中点 问题转化为: 求absoulte center,使得它到其他顶点最大值(偏心距)最小
先FLoyd求出任意两点最短路d[u,v] absoulte center必在某条边,枚举所有边u-v 假设它离u为a,设该点为r, f(r) = max{min(d[u,x]+a, w[u,v]-a+d[v,x])},则为半径了 至于确定a,Amber的文章上有比较具体的做法了,其实也就是有Kariv-Hakimi 算法了 觉得比较神奇的是枚举边,确定Absolute Center是针对变量a(r离u的距离)作目标的曲线
timus 1569是边权为1时的 */ #include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cstring> #include<cmath> #include<string> #include<cstdlib> #include<vector> #include<cstdio> #include<set> #include<list> #include<numeric> #include<cassert> #include<sstream> #include<ctime> #include<bitset> #include<functional>
using namespace std;
const int INF = 0x3f3f3f3f; const int MAXN = 501;
int w[MAXN][MAXN]; int dist[MAXN][MAXN]; int n, m; int cu, cv; int pre[MAXN], in[MAXN]; double dp[MAXN], ans;//为了更准确点。用了double
void update(int u, int v) { vector<pair<int,int> > vt, _vt; for (int i = 1; i <= n; i++) { vt.push_back(make_pair(dist[u][i], dist[v][i])); } sort(vt.begin(), vt.end()); //按照dist[u,i]从小到大排,最后需要考虑点是dist[u,i] < dist[u,j] && dist[v,i] > dist[u,j], i < j for (int i = 0; i < vt.size(); i++) { while(!_vt.empty() && _vt.back().second <= vt[i].second) { _vt.pop_back(); } _vt.push_back(vt[i]); } int D = INF;//diameter double a; if (_vt.size() == 1) { if (_vt[0].first < _vt[0].second) { a = 0; D = 2*_vt[0].first; } else { a = w[u][v]; D = 2*_vt[0].second; } }else { for (int i = 1; i < _vt.size(); i++) { if (D > w[u][v] + _vt[i-1].first + _vt[i].second) { a = (w[u][v] + _vt[i].second - _vt[i-1].first) / 2.0; D = w[u][v] + _vt[i-1].first + _vt[i].second; } } } if (D < ans) { cu = u; cv = v; ans = D; dp[u] = a; dp[v] = w[u][v] - a; } }
vector<pair<int, int> > edges;
void spfa() { fill(pre+1, pre+1+n, -1); fill(in+1, in+1+n, 0); for (int i = 1; i <= n; i++) { if (i != cu && i != cv) { dp[i] = INF; } } in[cu] = in[cv] = 1; queue<int> q; q.push(cu); q.push(cv); while (!q.empty()) { int t = q.front(); q.pop(); in[t] = 0; for (int i = 1; i <= n; i++) { if (w[t][i] != INF && dp[i] > dp[t] + w[t][i]) { dp[i] = dp[t]+w[t][i]; pre[i] = t; if (!in[i]) { in[i] = 1; q.push(i); } } } } edges.clear(); for (int i = 1; i <= n; i++) { if (pre[i] != -1) { edges.push_back(make_pair(min(i,pre[i]), max(i,pre[i]))); } } if (cv != cu) { edges.push_back(make_pair(min(cu,cv), max(cu,cv))); } return ; }
int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif for (;~scanf("%d%d", &n, &m); ) { fill(w[1], w[n+1], INF); int a, b, c; for (int i = 0; i < m; i++) { scanf("%d%d%d", &a, &b, &c); w[a][b] = w[b][a] = min(w[a][b], c); } for (int i = 1; i <= n; i++) {//? w[i][i] = 0; } memcpy(dist, w, sizeof dist); for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) if (dist[i][k] != INF) { for (int j = 1; j <= n; j++) dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]); } ans = INF; for (int i = 1; i <= n; i++) for (int j = i; j <= n; j++){ if (w[i][j] != INF) { update(i, j); } } cout<<ans<<endl; spfa(); sort(edges.begin(), edges.end()); for (vector<pair<int,int> >::iterator it = edges.begin() ; it != edges.end(); it++) { printf("%d %d\n", it->first, it->second); } } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|