UVALive 5713 Qin Shi Huang's National Road System(次小生成树)

题目:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3714

题目大意:n个平面上的城市要修建道路,每个城市有人,使他们连通。有一个人他能用法术造出任意一条道路。现在给你这 n 个点的二维坐标,设法术造的路两端的城市人口和为 A,B为人工造的道路长度之和,A 要尽量大,B要尽量小,让你求出最大的 A/B。

解题思路:和次小生成树的做法一样。先求出最小生成树,然后 dfs 遍历求出max_cost(u,v) 数组,即 u 到 v 最小生成树上唯一路径中边权的最大值。复杂度O(n^2)。然后枚举用法术搞哪一条道路,本来一棵树 n-1 条边,加上一条后,就变成了 n 条边,有一个环。把其中新加进去的这条边的两端的 max_cost ,换成0,tot_val 直接减掉就好。然后再求出最大值就行了。

代码如下:

#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
using namespace std;

const int EPS = 1e-8;

const int MAXN = 1111;

struct City
{
    int x,y,val;
    void read()
    {
        scanf("%d%d%d",&x,&y,&val);
    }
} city[MAXN];

struct Edge
{
    int s,t;
    double val;
    Edge(){}
    Edge(int a,int b,double c)
    {
        s = a;t = b;val = c;
    }
    bool operator < (const Edge& tmp) const
    {
        return val < tmp.val;
    }
} edge[MAXN*MAXN];

struct MST
{
    int n;
    int edge_count;
    void add_edge(int s,int t,double val)
    {
        edge[edge_count++] = Edge(s,t,val);
    }

    int fa[MAXN];
    int find_fa(int x)
    {
        if(fa[x] == x) return x;
        else return fa[x] = find_fa(fa[x]);
    }

    vector< pair<int,double> > G[MAXN];
    double tot_val;

    void krus()
    {
        sort(edge,edge+edge_count);
        for(int i = 0;i < n;i++)
            fa[i] = i,G[i].clear();
        tot_val = 0;
        for(int i = 0;i < edge_count;i++)
        {
            int a = edge[i].s;
            int b = edge[i].t;
            int fx = find_fa(a);
            int fy = find_fa(b);
            if(fx == fy) continue;
            fa[fx] = fy;
            tot_val += edge[i].val;
            G[a].push_back(make_pair(b,edge[i].val));
            G[b].push_back(make_pair(a,edge[i].val));
        }
    }

    double max_cost[MAXN][MAXN];
    vector<int> vec;

    void dfs(int u,int fa)
    {
        vec.push_back(u);
        for(int i = 0;i < G[u].size();i++)
        {
            int v = G[u][i].first;
            double val = G[u][i].second;
            if(v != fa)
            {
                for(int i = 0;i < vec.size();i++)
                    max_cost[vec[i]][v] = max_cost[v][vec[i]] = max(val,max_cost[vec[i]][u]);
                dfs(v,u);
            }
        }
    }

    void init(int n)
    {
        this->n = n;
        edge_count = 0;
    }

    void solve()
    {
        krus();
        memset(max_cost,0,sizeof(max_cost));
        vec.clear();
        dfs(0,-1);
    }
} mst;

double get_ans()
{
    double ans = 0;
    for(int i = 0;i < mst.edge_count;i++)
    {
        int s = edge[i].s;
        int t = edge[i].t;
        double tmp = mst.tot_val-mst.max_cost[s][t];
        ans = max(ans,(city[s].val+city[t].val+0.0)/tmp);
    }
    return ans;
}

double dis(int a,int b)
{
    return sqrt((city[a].x-city[b].x)*(city[a].x-city[b].x)+(city[a].y-city[b].y)*(city[a].y-city[b].y));
}

int main()
{
    int _;
    scanf("%d",&_);
    while(_--)
    {
        int n;
        scanf("%d",&n);
        for(int i = 0;i < n;i++)
            city[i].read();
        mst.init(n);
        for(int i = 0;i < n;i++)
            for(int j = i+1;j < n;j++)
                mst.add_edge(i,j,dis(i,j));
        mst.solve();
        double ans = get_ans();
        printf("%.2f\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值