#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <string> #include <cmath> #include <queue> #include <stack> #include <map> using namespace std; #define eps 1e-9 const int N = 1010; const int INF = 100000.0; int T, n; double maxcost[N][N]; int peo[N][N], pre[N]; double dis[N][N]; double d[N]; int x[N], y[N], p[N]; bool inTree[N][N], mark[N]; double prim() { for ( int i = 0; i < n; ++i ) d[i] = INF, pre[i] = -1; int v; double mi = INF, s1 = 0.0; bool vis[N]; memset( vis, 0, sizeof(vis)); d[0] = 0; for ( int u = 0; u < n; ++u ) { mi = INF; for ( int i = 0; i < n; ++i ) if ( !vis[i] && mi > d[i] ) mi = d[i], v = i; s1 += mi; vis[v] = true; if ( pre[v] >= 0 ) inTree[pre[v]][v] = inTree[v][pre[v]] = true; for ( int i = 0; i < n; ++i ) if ( !vis[i] && d[i] > dis[v][i] ) d[i] = dis[v][i], pre[i] = v; } return s1; } void determineM(int v) { for ( int u = 0; u < n; ++u ) { if ( !mark[u] && pre[u] == v ) { //inTree[u][v] = inTree[v][u] = true; mark[u] = true; for ( int x = 0; x < n; ++x ) if ( mark[x] && x != u ) maxcost[x][u] = maxcost[u][x] = max( maxcost[x][v], dis[u][v]); determineM(u); } } } double com( int x1, int y1, int x2, int y2 ) { return sqrt( 1.0*(x1-x2)*(x1-x2) + 1.0*(y1-y2)*(y1-y2) ); } int main() { scanf("%d", &T); while ( T-- ) { scanf("%d", &n); memset( inTree, 0, sizeof(inTree) ); memset( mark, 0, sizeof(mark)); //memset( maxcost, 0, sizeof(maxcost) ); for ( int i = 0;i < n; ++i ) scanf("%d%d%d", &x[i], &y[i], &p[i]); for ( int i = 0; i < n; ++i ) for ( int j = i+1; j < n; ++j ) dis[i][j] = dis[j][i] = maxcost[i][j] = maxcost[j][i] = com(x[i], y[i], x[j], y[j]), peo[i][j] = peo[j][i] = p[i] + p[j]; double noneM = prim(); //printf("noneM = %lf \n", noneM); mark[0] = 1; determineM(0); double ans = 0; for ( int i = 0; i < n; ++i ) for ( int j = i+1; j < n; ++j ) { //printf("i = %d, j = %d, mcost = %lf\n", i, j, maxcost[i][j]); if ( inTree[i][j] && ans < peo[i][j]/(noneM - dis[i][j]) ) ans = peo[i][j]/(noneM - dis[i][j]); else if ( !inTree[i][j] && ans < peo[i][j]/(noneM - maxcost[i][j]) ) ans = peo[i][j]/(noneM - maxcost[i][j]); } printf("%.2lf\n", ans); } }
要想A/B最大,那么我们能做的是保证B很小,那么B就是要在最小生成树上
先求最小生成树,然后枚举每一条边,一次按照求次小生成树的思路来求解最小的A/B。
求次小生成树,用prim算法,首先要记录前驱,然后标记在最小生成树上的边,标记边是为了之后的求解做准备,记录前驱是为求点对点的最小瓶颈路。
现在比较难理解的是就是求最小瓶颈路,之前学习过,现在复习一下具体思路:首先是用选择一个点作为根,然后依次遍历最小生成树的点,没经过一个点, 都要标记一下。用数组maxcost(x,y)记录点x 到 点y的路径上最长的边。如果magic边或者枚举的边不在MST上,那么删除的必定是两点之间路径上最长边。
求maxcost数组:初始化时maxcost(i, j)为i到j 的长度;然后选定的根开始,一路去求maxcost数组,原理是每当遍历到一个节点时,看这个节点的父节点与之前遍历过的所有节点的瓶颈路的长度和父节点到当前节点的长度比较,依次更新从其他节点到当前节点的maxcost的值,设父节点为v,当前节点是u,一遍力5节点是x,那么maxcost(x,u) = max( maxcost(x,v), dis(u, v)。动态规划的思想。
代码: