题目链接
题目大意:
秦始皇要在n个城市之间修筑一条道路使得任意两个城市均可连通。有个道士可以用法力帮忙修一条路。秦始皇希望其他的道路总长B最短且用法术连接的两个城市的人口之和A尽量大,因此下令寻找一个A / B的最大方案。
solution:这道题换个问法就是:在o(1),时间内求出最小生成树删去一条边后的权值。
我们可以先求出最小生成树的权值 minlen, 再o(n^2)求出节点间最小瓶颈路mx[u][v],那么原题中 B=minlen-mx[u][v]
, 再枚举u,v算出 A 就可以求出答案max(A/B )了。
如何求每对节点间最小瓶颈路 ??
先介绍几个概念
1.最小瓶颈生成树:给出加权无向图,求一颗生成树使得最大边权值尽量小。
怎么求?
我们先把边排序,然后从小到大,如果该边的两个节点没有被连通,那么就把它们加入生成树中。这个过程。。。就是Kruskal呀。 ====> 最小生成树就是最小瓶颈生成树
2.最小瓶颈路:给出加权无向图的两个节点u,v, 求出u到v的路径中最长边的最小值。
怎么搞??
先求出最小瓶颈生成树,在求u,v在最小瓶颈生成树上的路径的最长边。
3.每对节点的最小瓶颈路: 就是每对节点( u, v )之间的最小瓶颈路
显然,我们可以先求出最小生成树,再用dfs搞。
令: x为所有访问过的节点, u为当前节点, fa为当前节点的父亲节点
则有 mx[u][x]=mx[x][u]=max(mx[x][fa],w[x][fa])
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e3 + 5;
struct P{int x, y;int num;
}p[N];
struct E{int u, v;double dis;
}e[N*N];
struct Edge{int u, v;double w;Edge(int u,int v,double w):u(u),v(v),w(w){}
};
vector<Edge> edges;
vector<int> G[N];
int n, m;void addeage(int u, int v, double w){edges.push_back(Edge(u,v,w));int k=edges.size();G[u].push_back(k-1);
}int pa[N];
int find(int x){int r=x;while( r!=pa[r] ) r=pa[r];int i=x, j;while( i!=pa[i] ){j=pa[i];pa[i]=r;i=j;}return r;
}bool merge(int x, int y){x=find(x), y=find(y);if( x==y ) return false;pa[x]=y; return true;
} double minlen;
double mx[N][N];
vector<int> nodes;
bool cmp(E a, E b){return a.dis<b.dis;
}
void Kruskal(){int em=0;for ( int i=1; i<=n; i++ )for ( int j=i+1; j<=n; j++ ){e[em].u=i, e[em].v=j;e[em++].dis=sqrt( (double)(p[i].x-p[j].x)*(p[i].x-p[j].x) + (double) (p[i].y-p[j].y)*(p[i].y-p[j].y) );}sort(e,e+em,cmp);int num=0;minlen=0;for ( int i=1; i<=n; i++ ) pa[i]=i;for ( int i=0; i<em; i++ )if( merge(e[i].u,e[i].v) && num<n-1 ){num++;minlen+=e[i].dis;addeage(e[i].u,e[i].v,e[i].dis);addeage(e[i].v,e[i].u,e[i]. dis);}
}void dfs(int u, int fa, double dis){for ( int i=0; i<nodes.size(); i++ ){int id=nodes[i];mx[u][id]=mx[id][u]=max(mx[fa][id],dis);}nodes.push_back(u);for ( int i=0; i<G[u].size(); i++ ){Edge ee=edges[G[u][i]];if( ee.v==fa ) continue;dfs(ee.v,u,ee.w);}
}int main(){int T;scanf("%d", &T );while( T-- ){scanf("%d", &n );edges.clear();for ( int i=1; i<=n; i++ ) G[i].clear();nodes.clear();memset(mx,0,sizeof(mx));for ( int i=1; i<=n; i++ ){int x1, x2, x3;scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].num );} Kruskal();dfs(1,0,0);double ret=-1;for ( int i=1; i<=n; i++ )for ( int j=i+1; j<=n; j++ ){ret=max(ret,(double)(p[i].num+p[j].num)/(minlen-mx[i][j]));}printf("%.2lf\n",ret); }
}