HDU 4081 次小生成树变形记

点击打开链接

题意:n个点用n-1条边连起来,问两个点的人口A除以总的距离减去这两点的距离的最大值,表达能力有限,看看别人怎么翻译的吧,但是代码还是不错的......

思路:用到的是次小生成树中的记录i->j的最大距离,然后枚举每条边,因为已经求出了最小生成树,所以如果你加入这条边后,肯定会形成一个环(画图会有奇效),然后我们减去这个环的最大值,就可以保证B最小,遍历所有边后,输出最大值,而且这个环的最大值就是最小生成树上的一条边,这是肯定的,之前这里没有理解,想了大半天

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1010;
double num[maxn][maxn],dis[maxn],path[maxn][maxn];//path记录i->j的最大值
int X[maxn],Y[maxn],P[maxn],per[maxn],v[maxn],n;
bool vis[maxn][maxn];
double cal(int i,int j){
    double t=(double)(X[i]-X[j])*(X[i]-X[j])+(double)(Y[i]-Y[j])*(Y[i]-Y[j]);
    return sqrt(t);
}
double prim(){
    memset(v,0,sizeof(v));
    memset(vis,0,sizeof(vis));
    memset(path,0,sizeof(path));
    v[1]=1;
    double ans=0;
    for(int i=1;i<=n;i++){
        dis[i]=num[1][i];
        per[i]=1;
    }
    for(int i=1;i<=n;i++){
        int minidx=0;
        for(int j=1;j<=n;j++){
            if(!v[j]){
                if(minidx==0||dis[j]<dis[minidx]){
                    minidx=j;
                }
            }
        }
        vis[minidx][per[minidx]]=vis[per[minidx]][minidx]=1;//这条边是最小生成路的一条边,记录下来下面好判断
        ans+=num[minidx][per[minidx]];
        v[minidx]=1;
        for(int j=1;j<=n;j++){
            if(v[j]&&j!=minidx){
                path[minidx][j]=path[j][minidx]=max(path[j][per[minidx]],dis[minidx]);
                //因为最小生成树的prim算法跑得是点,kruskal跑得是边,所以我们每次更新这个点时,他不会是孤立的一个店或边,所以
                //依次类推,这个边肯定是最大值,我感觉这种题多画图看看有助于理解
            }
            if(!v[j]){
                if(dis[j]>num[minidx][j]){
                    dis[j]=num[minidx][j];
                    per[j]=minidx;
                }
            }
        }
    }
    return ans;
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d%d",&X[i],&Y[i],&P[i]);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                num[i][j]=cal(i,j);
            }
        }
        double ans=0;
        double sum=prim();
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(i==j) continue;
                if(vis[i][j]){
                    ans=max(ans,(P[i]+P[j])/(sum-num[i][j]));
                }else ans=max(ans,(P[i]+P[j])/(sum-path[i][j]));
            }
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

你可能感兴趣的:(数据结构,ACM,最短路,HDU)