題目大意:
現有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;
}