题目大意:
现有t个测例(t ≤ 10),每个测例都会给出n个点的坐标(2 < n ≤ 1,000),每个点的坐标信息形式诸如"X Y P",表示点的坐标为(X, Y),点权值为P,都为整型,其中0 ≤ X, Y ≤ 1,000,0 < P < 100,000,现要求n - 1条边将所有n个点都连通,并且将其中一条边的权值变为0,现要使变为0的边的两点的权值之和比上其它边权值之和最大,该如何构造这n - 1条以及如何挑选变为0的边才能是该比值最大,要求对于每个测例都输出该最大值,保留两位小数(边长即为两点的欧几里得距离)。
注释代码:
/*
* Problem ID : HDU 4081 Qin Shi Huang's National Road System
* Author : Lirx.t.Una
* Language : C++
* Run Time : 171 ms
* Run Memory : 18200 KB
*/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
//思路:
//先求MST使得n个点连通且边数为n - 1,并且使得总边权尽可能小
//这也使得点权比边权尽可能大
//然后在挑选边变为0测试ratio的大小,但是最小生成树可能有多个
//本来边(i, j)不在当前MST中,但是有可能在另一个MST中
//因此需要通过max_seg[i][j]换边得到另一种最小生成树
//但是g[i][j]并不一定等于max_seg[i][j],但是没有关系
//因为即使替换了也要将其边权变为0,就相当于将两点合为一点,因此没有关系
//因此最后逐个检查图中的每条边g[i][j],如果g[i][j]是当前MST中的点则非0边权为总边权减去g[i][j]
//否则非0边权就是总边权减去max_seg[i][j]
//最大点数
#define MAXN 1000
using namespace std;
struct Point {//每个点的坐标以及点权值
int x, y;
int w;
friend istream &
operator>>(istream &is, Point &p) {
is >> p.x >> p.y >> p.w;
return is;
}
int
POW(int a) { return a * a; }
double
operator^(Point &oth) {
return sqrt((double)( POW( x - oth.x ) + POW( y - oth.y ) ));
}
};
struct Node {//Prim堆优化中的结点
int u;
double d;
Node(void) {}
Node( int uu, double dd ) : u(uu), d(dd) {}
bool
operator<(const Node &oth)
const {
return d > oth.d;
}
};
double max_seg[MAXN + 1][MAXN + 1];
double g[MAXN + 1][MAXN + 1];
double d[MAXN + 1];
Point p[MAXN + 1];//表示每个点
int pre[MAXN + 1];
bool vis[MAXN + 1];
bool mst[MAXN + 1][MAXN + 1];
inline double
max( double a, double b ) {
return a > b ? a : b;
}
double//返回最小生成树的总边权
prim(int n) {
int i;
int u, v;
int nv;
double ans;
Node node;
priority_queue<Node> heap;
memset(vis, 0, sizeof(vis));
memset(mst, 0, sizeof(mst));
memset(max_seg, -1, sizeof(max_seg));
vis[1] = true;
for ( i = 2; i <= n; i++ ) {
d[i] = g[1][i];
pre[i] = 1;
heap.push(Node( i, d[i] ));
}
ans = 0.0;
nv = 1;
while (true) {//完全图必定有解,无需判断
while (true) {//必定有解
node = heap.top();
heap.pop();
if ( !vis[ u = node.u ] ) {
nv++;
ans += node.d;
mst[ pre[u] ][u] = true;
mst[u][ pre[u] ] = true;
for ( i = 1; i <= n; i++ )
if ( vis[i] ) {
max_seg[i][u] = max( max_seg[i][ pre[u] ], node.d );
max_seg[u][i] = max_seg[i][u];
}
vis[u] = true;
break;
}
}
if ( nv == n ) break;
for ( v = 2; v <= n; v++ )
if ( !vis[v] && g[u][v] < d[v] ) {
d[v] = g[u][v];
pre[v] = u;
heap.push(Node( v, d[v] ));
}
}
return ans;
}
int
main() {
int t;
int n;
int i, j;
double B;//MST边的总权值
double r;//最后的比例
scanf("%d", &t);
while ( t-- ) {
scanf("%d", &n);
for ( i = 1; i <= n; i++ ) cin >> p[i];
for ( i = 1; i <= n; i++ )
for ( j = i + 1; j <= n; j++ ) {
g[i][j] = p[i] ^ p[j];
g[j][i] = g[i][j];
}
r = -1.0;//初始化为一个极小值
B = prim(n);
for ( i = 1; i <= n; i++ )
for ( j = i + 1; j <= n; j++ )
if ( mst[i][j] )//MST中的边之间边为0试一下
r = max( r, ( p[i].w + p[j].w ) / ( B - g[i][j] ) );
else//非MST中的边g[i][j]替换max_seg[i][j]再变为0试一下
r = max( r, ( p[i].w + p[j].w ) / ( B - max_seg[i][j] ) );
printf("%.2lf\n", r);
}
return 0;
}
无注释代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#define MAXN 1000
using namespace std;
struct Point {
int x, y;
int w;
friend istream &
operator>>(istream &is, Point &p) {
is >> p.x >> p.y >> p.w;
return is;
}
int
POW(int a) { return a * a; }
double
operator^(Point &oth) {
return sqrt((double)( POW( x - oth.x ) + POW( y - oth.y ) ));
}
};
struct Node {
int u;
double d;
Node(void) {}
Node( int uu, double dd ) : u(uu), d(dd) {}
bool
operator<(const Node &oth)
const {
return d > oth.d;
}
};
double max_seg[MAXN + 1][MAXN + 1];
double g[MAXN + 1][MAXN + 1];
double d[MAXN + 1];
Point p[MAXN + 1];
int pre[MAXN + 1];
bool vis[MAXN + 1];
bool mst[MAXN + 1][MAXN + 1];
inline double
max( double a, double b ) {
return a > b ? a : b;
}
double
prim(int n) {
int i;
int u, v;
int nv;
double ans;
Node node;
priority_queue<Node> heap;
memset(vis, 0, sizeof(vis));
memset(mst, 0, sizeof(mst));
memset(max_seg, -1, sizeof(max_seg));
vis[1] = true;
for ( i = 2; i <= n; i++ ) {
d[i] = g[1][i];
pre[i] = 1;
heap.push(Node( i, d[i] ));
}
ans = 0.0;
nv = 1;
while (true) {
while (true) {
node = heap.top();
heap.pop();
if ( !vis[ u = node.u ] ) {
nv++;
ans += node.d;
mst[ pre[u] ][u] = true;
mst[u][ pre[u] ] = true;
for ( i = 1; i <= n; i++ )
if ( vis[i] ) {
max_seg[i][u] = max( max_seg[i][ pre[u] ], node.d );
max_seg[u][i] = max_seg[i][u];
}
vis[u] = true;
break;
}
}
if ( nv == n ) break;
for ( v = 2; v <= n; v++ )
if ( !vis[v] && g[u][v] < d[v] ) {
d[v] = g[u][v];
pre[v] = u;
heap.push(Node( v, d[v] ));
}
}
return ans;
}
int
main() {
int t;
int n;
int i, j;
double B;
double r;
scanf("%d", &t);
while ( t-- ) {
scanf("%d", &n);
for ( i = 1; i <= n; i++ ) cin >> p[i];
for ( i = 1; i <= n; i++ )
for ( j = i + 1; j <= n; j++ ) {
g[i][j] = p[i] ^ p[j];
g[j][i] = g[i][j];
}
r = -1.0;
B = prim(n);
for ( i = 1; i <= n; i++ )
for ( j = i + 1; j <= n; j++ )
if ( mst[i][j] )
r = max( r, ( p[i].w + p[j].w ) / ( B - g[i][j] ) );
else
r = max( r, ( p[i].w + p[j].w ) / ( B - max_seg[i][j] ) );
printf("%.2lf\n", r);
}
return 0;
}