UVA1494 Qin Shi Huang's National Road System 题解(次最小生成树)

题目链接

题目大意

给定n个点的点权及相互间的边权,求一棵树,其中一条边的边权变为0,树的比率值为该0值边所连的两点的点权和/剩下的树边和。

求这个值最大是多少。

题目思路

这题要用到次小生成树的思想,即找到最小生成树,然后添加一条边构成环,再删掉环中属于最小树的最大边,用这种方法遍历所有边以

找到最终长度。

易错警示

1:注意初始化的时候要仔细

2:注意边长double类型

3:求i到j的所有路线中最长的线段,dfs函数有点玄学(可能是我太菜的原因

代码

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=1e3+3;
int t,n,a[maxn],b[maxn],p[maxn],cnt,fa[maxn];
double d[maxn][maxn],ans,sum;//注意为double类型
vector<int>dis[maxn];
bool vis[maxn];
struct node
{
    int l,r;
    double len;
}e[maxn*maxn];
bool cmp(node a,node b)
{
    return a.len<b.len;
}
int findd(int x)
{
    if(x==fa[x])
        return x;
    return fa[x]=findd(fa[x]);
}
void dfs(int l,int mid)//最关键也是最难的函数
{
    vis[mid]=1;//到了就标记
    for(int i=0;i<dis[mid].size();i++)
    {
        int r=dis[mid][i];
        if(vis[r]==0)//没走过
        {
              d[l][r]=max(d[l][mid],d[mid][r]);
              dfs(l,r);
        }
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        cnt=0,ans=0.0,sum=0.0;//初始化
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            dis[i].clear();//这个清空千万别忘了
            fa[i]=i;
            scanf("%d%d%d",&a[i],&b[i],&p[i]);
        }
        for(int i=1;i<n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                cnt++;
                e[cnt].l=i,e[cnt].r=j;
                e[cnt].len=sqrt((a[i]-a[j])*(a[i]-a[j])+(b[i]-b[j])*(b[i]-b[j]));
            }
        }
        sort(e+1,e+1+cnt,cmp);
        for(int i=1;i<=cnt;i++)//求最小生成树
        {
            int x=e[i].l;
            int y=e[i].r;
            if(findd(x)!=findd(y))
            {
                fa[findd(x)]=findd(y);
                dis[x].push_back(y);
                dis[y].push_back(x);
                sum=sum+e[i].len;
                d[x][y]=e[i].len;
                d[y][x]=e[i].len;
            }
        }
        for(int i=1;i<=n;i++)//查找i到j的最长的一条线段
        {
            memset(vis,0,sizeof(vis));
            dfs(i,i);
        }
        for(int i=1;i<n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                ans=max(ans,1.0*(p[i]+p[j])/(sum-d[i][j]));
            }
        }
        printf("%.2f\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值