最小生成树prim 求得 树上两点之间的最大最小值

#include<iostream>
#include<cmath>
#include<cstring>

using namespace std;

const int N = 1010,M = N * 2;

int head[N],to[M],last[M];double w[M];int cnt;
void add(int a,int b,double c){
    to[++cnt] = b;
    w[cnt] = c;
    last[cnt] = head[a];
    head[a] = cnt;
}

struct node{
    int x,y,z;
}a[N];

double dis[N][N];
double get(int i,int j){
    return sqrt((a[i].x - a[j].x) * (a[i].x - a[j].x) + (a[i].y - a[j].y) * (a[i].y - a[j].y));
}

int n;
double sum;
double lowcost[N];
int flag[N];
int dd[N],mst[N][N];double maxd[N][N];
void mintree(){
    memset(flag,0,sizeof flag);
    memset(maxd,0,sizeof maxd);
    memset(mst,0,sizeof mst);
    memset(dd,0,sizeof dd);
    int now = 1;
    for(int i = 1; i <= n; i++){
        lowcost[i] = dis[1][i];
        dd[i] = 1;
    }
    flag[1] = 1;
    lowcost[1] = 0;
    for(int i = 1; i <= n - 1; i++){
        double minn = 1e9;
        int nex = 0;
        for(int j = 1; j <= n; j++){
            if(minn > lowcost[j] && lowcost[j] != 0){
                minn = lowcost[j];
                nex = j;
            }
        }
        lowcost[nex] = 0;
        flag[nex] = 1;
        sum += minn;
        mst[nex][dd[nex]] = 1;
        mst[dd[nex]][nex] = 1;
        add(nex,dd[nex],dis[dd[nex]][nex]);
        add(dd[nex],nex,dis[dd[nex]][nex]);
        for(int j = 1; j <= n; j++){
            if(flag[j] && dis[nex][j] < 1e9) maxd[nex][j] = maxd[j][nex] = max(maxd[j][dd[nex]],minn);
            if(dis[nex][j] < lowcost[j]){
                lowcost[j] = dis[nex][j];
                dd[j] = nex;
            }
        }

    }
}

int LOG[N * 2];
int depth[N * 2],st[N * 2][20],eu[N * 2],ans;
double st2[N][20];int fa[N][20],id[N];
void dfs(int x,int pre){
    depth[x] = depth[pre] + 1;
    eu[++ans] = x,id[x] = ans;
    for(int i = head[x]; i != -1; i = last[i]){
        int j = to[i];
        if(j == pre) continue;
        st2[j][0] = w[i];
        fa[j][0] = x;
        dfs(j,x);
        eu[++ans] = x;
    }
}

int MIN(int x,int y){
    if(depth[x] < depth[y]) return x;
    return y;
}

int lca(int x,int y){
    if(x > y) swap(x,y);
    int k = LOG[y - x + 1];
    return MIN(st[x][k],st[y - (1 << k) + 1][k]);
}

double query(int start,int end){
    int LCA = lca(id[start],id[end]);
    double maxn = 0;
    for(int i = 10; i >= 0; i--){
        if(depth[fa[start][i]] >= depth[LCA]){
            maxn = max(maxn,st2[start][i]);
            start = fa[start][i];
        }
    }

    for(int i = 10; i >= 0; i--){
        if(depth[fa[end][i]] >= depth[LCA]){
            maxn = max(maxn,st2[end][i]);
            end = fa[end][i];
        }
    }

    return maxn;
}


int main(){
    int t;
    cin >> t;
    while(t--){
        cin >> n;
        memset(head,-1,sizeof head);
        cnt = 0,ans = 0,sum = 0;
        for(int i = 1; i <= n; i++){
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
        }

        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++) dis[i][j] = 1e9;
        }
        for(int i = 1; i <= n; i++){
            for(int j = i + 1; j <= n; j++){
                dis[i][j] = get(i,j);
                dis[j][i] = dis[i][j];
            }
        }

        mintree();
        dfs(1,0);

        for(int i = 1; i <= ans; i++) st[i][0] = eu[i];
        for(int i = 2; i <= ans; i++) LOG[i] = LOG[i >> 1] + 1;
        for(int j = 1; j <= 19; j++){
        for(int i = 1; i + (1 << j) - 1 <= ans; i++){
                st[i][j] = MIN(st[i][j - 1],st[i + (1 << (j - 1))][j - 1]);
            }
        }

        for(int j = 1; j <= 19; j++){
        for(int i = 1; i <= n; i++){
                fa[i][j] = fa[fa[i][j - 1]][j - 1];
                st2[i][j] = max(st2[i][j - 1],st2[fa[i][j - 1]][j - 1]);
            }
        }


        double maxn = 0;
        for(int i = 1; i <= n; i++){
            for(int j = i + 1; j <= n; j++){
                    //cout << i << " " << j <<" "<< a[i].z + a[j].z << " " << sum << " " << maxd[i][j] << "asd" << endl;
                if(!mst[i][j]) maxn = max(maxn,(a[i].z + a[j].z) * 1.0 / (sum - query(i,j)));
                else maxn = max(maxn,(a[i].z + a[j].z) * 1.0 / (sum - dis[i][j]));
            }
        }


        printf("%.2lf\n",maxn);

    }




    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值