hdoj 4081

20 篇文章 0 订阅
4 篇文章 0 订阅

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 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值