HDU 4081 次小生成树变形记

点击打开链接

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

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

#include 
#include 
#include 
#include 
#include 
#include 
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]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;
}

你可能感兴趣的:(数据结构,最短路,线段树)