HDU 4081 最小生成树(或者次小生成树)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4081

Problem Description

There were n cities in China and Qin Shi Huang wanted them all be connected by n-1 roads, in order that he could go to every city from the capital city Xianyang.
Although Qin Shi Huang was a tyrant, he wanted the total length of all roads to be minimum,so that the road system may not cost too many people's life. A daoshi (some kind of monk) named Xu Fu told Qin Shi Huang that he could build a road by magic and that magic road would cost no money and no labor. But Xu Fu could only build ONE magic road for Qin Shi Huang. So Qin Shi Huang had to decide where to build the magic road. Qin Shi Huang wanted the total length of all none magic roads to be as small as possible, but Xu Fu wanted the magic road to benefit as many people as possible ---- So Qin Shi Huang decided that the value of A/B (the ratio of A to B) must be the maximum, which A is the total population of the two cites connected by the magic road, and B is the total length of none magic roads.
Would you help Qin Shi Huang?
A city can be considered as a point, and a road can be considered as a line segment connecting two points.

Input

The first line contains an integer t meaning that there are t test cases(t <= 10).
For each test case:
The first line is an integer n meaning that there are n cities(2 < n <= 1000).
Then n lines follow. Each line contains three integers X, Y and P ( 0 <= X, Y <= 1000, 0 < P < 100000). (X, Y) is the coordinate of a city and P is the population of that city.
It is guaranteed that each city has a distinct location.

Output

For each test case, print a line indicating the above mentioned maximum ratio A/B. The result should be rounded to 2 digits after decimal point.

Sample Input

2

4

1 1 20

1 2 30

200 2 80

200 1 100

3

1 1 20

1 2 30

2 2 40

Sample Output

65.00

70.00

题目大意:

题意:给出一些点的坐标代表一些城市并给出一个值代表这个城市的人口,总共有n-1条道路,其中有一条道路是魔法道路,这条道路没有权值,这条道路所连接的两城市的人口数和为A然后其余n-2条道路的权值之和为B,问A/B的最大值为多少

输入:

第一行 样例数T

第二行 n 这个树有几个点

接下来 n 行 表示点(城市)坐标(x,y)和权值w(人口数)

思路:

此题跟次小生成树没多大关系,只是涉及到最小生成树的遍历问题。解题思路就是先求出最小生成树,存储这棵树,然后再在这棵树上进行去边操作,此时的两颗树上人口数最多的两个城市人口数的和 去除以 最小生成树的值减去此边的值 后的商,求这个商最大可能是多少。

This is the code

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<sstream>
#include<stack>
#include<string>
#include<set>
#include<vector>
using namespace std;
#define PI acos(-1.0)
#define EPS 1e-8
#define LL long long
#define ULL unsigned long long     //1844674407370955161
#define INT_INF 0x7f7f7f7f      //2139062143
#define LL_INF 0x7f7f7f7f7f7f7f7f //9187201950435737471
// ios::sync_with_stdio(false);
// 那么cin, 就不能跟C的 scanf,sscanf, getchar, fgets之类的一起使用了。
const int dr[]= {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[]= {-1, 1, 0, 0, -1, 1, -1, 1};
struct node
{
    int x,y;
    double w;//花费
} ;
node a[1050];
struct Node
{
    int u;
    int v;
    double dis;//距离
    Node() {}
    Node(int u,int v,double dis):u(u),v(v),dis(dis) { }
    bool operator < (const Node &rhs)const
    {
        return dis > rhs.dis;//小根推,距离短的在前面的在前面
    }
};

Node b[1050];//储存树
priority_queue<Node> edges;
int fa[1050];
bool vis[1050];
vector<int> G[1050];
double sum=0;//最短距离
double peo;

int Find(int x)
{
    if(fa[x]==x)
        return x;
    return Find(fa[x]);
}

inline double S(int x1,int y1,int x2,int y2)//求距离
{
    return sqrt(double((x1-x2)*(x1-x2))+double((y1-y2)*(y1-y2)));
}

inline void init(int n)//一定要初始化
{
    for(int i=0; i<=n; ++i)
    {
        fa[i]=i;
        G[i].clear();
    }
    sum=0;
    while(!edges.empty())
        edges.pop();
}

void Kruskal(int n)//求最小生成树
{
    int cnt=0;
    while(!edges.empty())
    {

        Node x=edges.top();
        //cout<<x.u<<" "<<x.v<<" "<<x.dis<<endl;
        edges.pop();
        int u=Find(x.u);
        int v=Find(x.v);
        if(u!=v)
        {
            fa[u]=v;
            b[cnt++]=x;
            sum+=x.dis;
            G[x.u].push_back(x.v);//记录与这个点连接的有哪些点
            G[x.v].push_back(x.u);
        }
        if(cnt==n)
            break;
    }
}

void dfs(int u)//寻找人口数两
{
    vis[u]=true;//表示城市已经寻找过
    peo=max(peo,a[u].w);
    for(int i=0;i<G[u].size();++i)
        if(!vis[G[u][i]])
            dfs(G[u][i]);

}

void Slove(int n)
{
    double ans=-1;
    for(int i=0; i<n; ++i)
    {
        memset(vis,false,sizeof(vis));
        double Num=0;
        int u=b[i].u;
        int v=b[i].v;
         //寻找U这边人口最大的城市
        vis[v]=true;//将U-V两个边分隔开
        peo=0;
        dfs(u);
        Num+=peo;//累加人口数量
        //寻找V这边人口最大的城市
        peo=0;
        dfs(v);
        Num+=peo;
        ans = max(ans,Num/(sum-b[i].dis));//计算A/B
    }
    printf("%0.2lf\n",ans);
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d",&n);
        init(n);
        for(int i=1; i<=n; ++i)
        {
            scanf("%d%d%lf",&a[i].x,&a[i].y,&a[i].w);
            for(int j=1; j<i; ++j)
            {
                double tem=S(a[i].x,a[i].y,a[j].x,a[j].y);//长度
                edges.push(Node(j,i,tem));
            }
        }
        Kruskal(n-1);
        Slove(n-1);
    }
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值