HDU 4081 Qin Shi Huang‘s National Road System(Kruskal重构树+枚举+倍增优化)

题目链接
题目链接:给你n个点,每个点都有权值,可以免费连接两个点,然后再选择n-2条边构成一个生成树,使得免费连接的两个点的权值和/n-2条边的长度和比值最大。输出这个最大值。
分析:很容易可以想到枚举哪两个点免费连接,然后用并查集维护,构建最小生成树,但这样做明显不现实,n=1000,时间复杂度不允许,所以否决这个方案。
反过来思考,如果不是在枚举点后求最小生成树,而是枚举最小生成树上的两点,因为树上路径是唯一的,所以求出这两点间最大的一条边,用总权值减去这一条边的长度,最后维护一个最小值就行了。
求路径的最小值这题的范围可以直接dfs暴力求,也可以树链剖分或者倍增。
这里用的倍增

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<vector>
#define MAIN main
#define PII pair<int,int>
#define x first
#define y second
using namespace std;
typedef long long ll;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const int N=1e3+10;
int sgn(double x)
{
    
    
    if(fabs(x)<eps) return 0;
    return x>0?1:-1;
}
struct edge
{
    
    
    int v,next;
    double w;
}e[(N*N)<<1];
int head[N],cnt;
void add(int u,int v,double w)
{
    
    
    e[++cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
struct node
{
    
    
    int u,v;
    double w;
    bool operator < (const node &a)const {
    
    
        return w<a.w;
    }
}ee[N*N];
struct Point
{
    
    
    double x,y;
    int num;
    Point (double x=0,double y=0,int num=0):x(x),y(y),num(num){
    
    }
};
Point p[N];
int n,m;
double Distance(Point a,Point b)
{
    
    
    double d1=a.x-b.x;
    double d2=a.y-b.y;
    return sqrt(d1*d1+d2*d2);
}
int f[N];
int Find(int x)
{
    
    
    if(f[x]!=x) f[x]=Find(f[x]);
    return f[x];
}
int fa[N],anc[N][30],dep[N];
double cost[N],maxcost[N][30];
void dfs(int u,int p)
{
    
    
    fa[u]=p;
    dep[u]=dep[p]+1;
    for(int i=head[u];i;i=e[i].next)
    {
    
    
        int v=e[i].v;
        if(v==p) continue;
        cost[v]=e[i].w;
        dfs(v,u);
    }
}
void pre()
{
    
    
    for(int i=1;i<=n;i++){
    
    
        anc[i][0]=fa[i];maxcost[i][0]=cost[i];
        for(int j=1;(1<<j)<n;j++) anc[i][j]=-1;
    }
    for(int j=1;(1<<j)<n;j++){
    
    
        for(int i=1;i<=n;i++){
    
    
            if(anc[i][j-1]!=-1){
    
    
                int a=anc[i][j-1];
                anc[i][j]=anc[a][j-1];
                maxcost[i][j]=max(maxcost[i][j-1],maxcost[a][j-1]);
            }
        }
    }
}
double query(int u,int v)
{
    
    
    if(dep[u]<dep[v]) swap(u,v);
    int log;
    for(log=1;(1<<log)<=dep[u];log++);
    log--;
    double ans=-1e10;
    for(int i=log;i>=0;i--){
    
    
        if(dep[u]-(1<<i)>=dep[v]){
    
    
            ans=max(ans,maxcost[u][i]);
            u=anc[u][i];
        }
    }
    if(u==v) return ans;
    for(int i=log;i>=0;i--){
    
    
        if(anc[u][i]!=anc[v][i]&&anc[u][i]!=-1){
    
    
            ans=max(ans,maxcost[u][i]);u=anc[u][i];
            ans=max(ans,maxcost[v][i]);v=anc[v][i];
        }
    }
    ans=max(ans,cost[u]);
    ans=max(ans,cost[v]);
    return ans;
}
double mst;
void solve()
{
    
    
    double ans=-1e10;
    double sum;
    for(int i=1;i<=n;i++){
    
    
        for(int j=i+1;j<=n;j++){
    
    
            double max_edge=query(i,j);
            mst-=max_edge;
            sum=p[i].num+p[j].num;
            ans=max(ans,sum/mst);
            mst+=max_edge;
        }
    }
    printf("%.2f\n",ans);
}
int MAIN()
{
    
    
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        cnt=0;
        memset(head,0,sizeof(head));
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
    
    
            scanf("%lf%lf%d",&p[i].x,&p[i].y,&p[i].num);
        }
        m=0;
        for(int i=1;i<=n;i++){
    
    
            for(int j=i+1;j<=n;j++){
    
    
                ee[++m].u=i;
                ee[m].v=j;
                ee[m].w=Distance(p[i],p[j]);
            }
        }
        sort(ee+1,ee+m+1);
        for(int i=1;i<=n;i++) f[i]=i;
        int k=0;
        mst=0;
        for(int i=1;i<=m;i++)
        {
    
    
            int r1=Find(ee[i].u);
            int r2=Find(ee[i].v);
            if(r1==r2) continue;
            k++;
            f[r2]=r1;
            mst+=ee[i].w;
            add(ee[i].u,ee[i].v,ee[i].w);
            add(ee[i].v,ee[i].u,ee[i].w);
            //printf("%d %d %.2f\n",ee[i].u,ee[i].v,ee[i].w);
            if(k==n-1) break;
        }
        dfs(1,0);
        fa[1]=-1;
        pre();
        solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/amazingee/article/details/113700242