HDU4081 Qin Shi Huang's National Road System

本文解析了一个关于次小生成树的问题,通过求最小生成树并枚举每条边进行优化,实现寻找特定条件下的人口比例最大值。使用C++实现了Prim算法,并详细记录了解决过程中的调试经历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出n个城市的坐标和人口,两个间的距离是欧几里得距离,可以免距离连接一条路径,要是免费连的那两个城市的人口比上生成树的距离比值最大。。

次小生成树,先求出最小生成树,然后枚举生成树上每一条边,把他去掉,就形成来两个连通块,从两个连通块中分别找到人口最大的城市,免费连接起来,所以就是这两个人口加起来比上去掉一条边的最小生产数的权值,可以在求最小生成树时把生产树上的边存起来。。。

吐糟下。。。。用邻接表,不是MLE,就是RE(爆栈),弄得稀里糊涂,后来换成vector就变WA了。。。然后发现欧几里得距离居然弄成了曼哈顿距离。。。然后A了

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=1010;
const int INF=1<<30;
double cost[MAXN][MAXN];
double lowcost[MAXN];
int pre[MAXN];
vector<int> G[MAXN];
struct Node
{
    int x,y;
    double val;
}p[MAXN];
double prim(int v0,int n)
{
    int i,j;
    double ans=0;
    memset(pre,-1,sizeof(pre));
    for(i=1;i<=n;i++)
    {
        lowcost[i]=cost[v0][i];
        pre[i]=v0;
    }
    for(i=1;i<n;i++)
    {
        double mincost=(double)INF;
        int minone=-1;
        for(j=1;j<=n;j++)
        {
            if(lowcost[j]&&mincost>lowcost[j])
            {
                mincost=lowcost[j];
                minone=j;
            }
        }
        ans+=mincost;
        G[pre[minone]].push_back(minone);
        G[minone].push_back(pre[minone]);
        lowcost[minone]=0;
        for(j=1;j<=n;j++)
        {
            if(lowcost[j]>cost[minone][j])
            {
                lowcost[j]=cost[minone][j];
                pre[j]=minone;
            }
        }
    }
    return ans;
}
double maxp;
void dfs(int u,int fa)
{
    if(p[u].val>maxp)
        maxp=p[u].val;
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v==fa)
            continue;
        dfs(v,u);
    }
}
double dist(Node a,Node b)
{
    return sqrt(1.0*(a.x-b.x)*(a.x-b.x)+1.0*(a.y-b.y)*(a.y-b.y));
}
double solve(int n)
{
    int i,j;
    double mst=prim(1,n);
    double ans=0;
    for(i=1;i<=n;i++)
    {
        for(j=0;j<G[i].size();j++)
        {
            int v=G[i][j];
            double temp=0;
            maxp=0;
            dfs(v,i);
            temp+=maxp;
            maxp=0;
            dfs(i,v);
            temp+=maxp;
            ans=max(ans,temp*1.0/(mst-cost[i][v]));
        }
    }
    return ans;

}
int main()
{
    int t,n,i,j;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            G[i].clear();
        for(i=1;i<=n;i++)
            scanf("%d%d%lf",&p[i].x,&p[i].y,&p[i].val);
        for(i=1;i<=n;i++)
        {
            for(j=i+1;j<=n;j++)
                cost[i][j]=cost[j][i]=dist(p[i],p[j]);
        }
        printf("%.2f\n",solve(n));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值