Qin Shi Huang's National Road System
今天作比赛,做了这个题目,整个比赛中就只做了这一道= =。太弱了= = 。这个题目是最小生成树+树形DP。要求的是A/B , B是非特殊边的距离和,而A是特殊边两端城市的人口之和,由于要使得比值尽量的大,所以我们肯定距离要最短。我们可以首先求一下最小生成树,然后直接枚举每条边,去除该边后所能产生的最大比值。我们需要用一个数组popu[i],来保存以i为根节点的人口数最多的城市的人口。然后就是求完根后怎么转换过去。我们只需要找城市i的人口的数目,以及城市i的子节点除j外的最多的人口。所以只需要枚举一下就可以了。求最短路的时候直接用prim即可。
/*
author: csu_chenan
time: 62ms
memory:1636K
*/
#include <iostream>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>
#include <queue>
using namespace std ;
#define MAXN 1005
struct Point{
int x ;
int y ;
int population ;
}point[MAXN];
typedef pair< double , int> pii ;
double dist[MAXN] ;
double rate ;
double sum ;
int n ;
bool visit[MAXN] ;
int pre[MAXN] ;
int popu[MAXN] ;
vector<int> G[MAXN] ;
double distan(Point a , Point b){
int z = ( a.x - b.x ) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) ;
return (double) ( sqrt(z * 1.0) ) ;
}
void init(){
for(int i = 0 ; i < n ; i ++){
G[i].clear() ;
}
memset(popu , 0 , sizeof(popu)) ;
}
void MSP(int src){
memset(visit , 0 , sizeof(visit)) ;
memset(pre , -1 , sizeof(pre)) ;
priority_queue<pii, vector<pii>, greater<pii> > Q ;
for(int i = 0 ; i < n ; i ++){
dist[i] = distan(point[i] , point[src]) ;
pre[i] = src ;
visit[i] = 0 ;
Q.push(make_pair(dist[i] , i)) ;
}
sum = 0.0 ;
int k = 0 ;
while(!Q.empty()){
pii p = Q.top() ;
Q.pop() ;
int v = p.second ;
if(visit[v])
continue ;
if(k == n)
break ;
k ++ ;
visit[v] = 1 ;
if(pre[v] == -1)
continue ;
if(pre[v] != v){
G[pre[v] ].push_back(v) ;
}
sum = sum + dist[v] ;
for(int i = 0 ; i < n ; i ++){
if(visit[i])
continue ;
if(pre[i] == v)
continue ;
double d = distan(point[v] , point[i]) ;
if(d < dist[i]){
dist[i] = d ;
pre[i] = v ;
Q.push( make_pair(dist[i],i) ) ;
}
}
}
}
void dfs(int v ){
int len = G[v].size() ;
popu[v] = point[v].population ;
for(int i = 0 ; i < len ; i ++){
dfs(G[v][i]) ;
popu[v] = popu[v] > popu[ G[v][i] ] ? popu[v] : popu[ G[v][i] ] ;
}
}
void dfs2(int v , int far){
int len = G[v].size() ;
int nmax ;
for(int i = 0 ; i < len ; i ++){
int u = G[v][i] ;
nmax = far > point[v].population ? far : point[v].population ;
for(int k = 0 ; k < len ; k ++){
if(G[v][k] == u)
continue ;
if(nmax < popu[ G[v][k] ]){
nmax = popu[ G[v][k] ] ;
}
}
double d = (nmax + popu[u]) / (sum - dist[u]) ;
if(rate < d ){
rate = d ;
}
dfs2(u , nmax) ;
}
}
int main(){
int t ;
scanf("%d" , &t) ;
while(t--){
scanf("%d" , &n) ;
init();
for(int i = 0 ; i < n ; i ++){
scanf("%d%d%d" , &point[i].x , &point[i].y , &point[i].population) ;
}
MSP(0) ;
dfs(0) ;
rate = 0.0 ;
dfs2(0,0) ;
printf("%.2lf\n" , rate) ;
}
return 0 ;
}