hdu4081Qin Shi Huang's National Road System 次小生成树

//给出每点的坐标和其到人口量,找一个生成树,其中有一条边造价为0
//问A/B的最大值,A这条边连接的两个点的人口之和
//B除了这条边以外的其他边的长度之和
//先找到最小生成树,然后枚举所有边,如果这条边是最小生成树上的边,
//直接计算A/(sum-edge) ,如果不是,那么这条边加在最小生成树上会出现一个
//环,去除这个环中的最长的边依然是一棵树,
//用dp[u][v] 表示在最小生成树中从u到v的唯一路径所经过的最长边的大小
//dp[u][v[i]] = dp[v[i]][u]= max(map[F[u]][u] , dp[F[u]][v[i]])  ;
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std ;
const int maxn = 1010 ;
const int inf = 0x3f3f3f3f ;
double dp[maxn][maxn] ;
double map[maxn][maxn] ;
double x[maxn] , y[maxn] , p[maxn] ;
int F[maxn] ;int vis[maxn] ;
int v[maxn] ;double dis[maxn] ;
int n ;
double prim()
{
 int len = 0 ;
 memset(vis ,0 ,sizeof(vis)) ;
 memset(dp , 0 , sizeof(dp)) ;
 for(int i = 2;i <=n; i++)
 dis[i] = inf ;
 dis[1] = 0 ;F[1] = 1 ;
 v[++len] = 1 ;
 double ans = 0 ;
 while(1)
 {
 double mi = inf ;int u ;
 for(int i = 1;i <= n;i++)
 if(!vis[i]&&dis[i] < mi)
 mi = dis[u = i] ;
 if(mi == inf)break;
 vis[u] = 1;
 ans += mi ;
 for(int i = 1;i <= len ;i++)
 dp[u][v[i]] = dp[v[i]][u]= max(map[F[u]][u] , dp[F[u]][v[i]]) ;
 v[++len] = u ;
 for(int i = 1;i <= n;i++)
 if(!vis[i] && map[u][i] < dis[i])
 {
 dis[i] = map[u][i] ;
 F[i] = u ;
 }
 }
 return ans ;
}
int main()
{
 //freopen("in.txt" ,"r" , stdin) ;
 int t ;
 scanf("%d" , &t) ;
 while(t--)
 {
 scanf("%d" , &n) ;
 for(int i = 1;i <= n;i++)
 {
 scanf("%lf%lf%lf" , &x[i] , &y[i] , &p[i]) ;
 for(int j = 1;j <= i;j++)
 map[i][j] = map[j][i] = sqrt((x[i]-x[j])*(x[i]-x[j]) + (y[i] - y[j])*(y[i]-y[j])) ;
 }
 double sum = prim() ;
 double ans = 0 ;
 for(int i = 1;i <= n;i++)
 for(int j = 1; j < i ;j++)
 ans = max(ans , (p[i] + p[j])/(sum - dp[i][j])) ;
 printf("%.2lf\n" , ans) ;
 }
 return 0 ;
}
















你可能感兴趣的:(dp,最小生成树)