LA 5713

LA 5713

要求A/B最大,那我们先保证B最小,然后枚举A。先求出最小生成树,并在树上深搜,记录下maxcost[u][v],即树上点u到点v之间的最长的边。
再枚举A,即枚举法术边的两个端点i和j,删去树中i到j路径上的最长边,加入用法术边(i,j)。此时最小生成树权值变成了sum-maxcost[i][j]。
求出min((W[i]+W[j])/(sum-maxcost[i][j]))即可。

#include<map>
#include<cmath>
#include<ctime>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<string>
#define LL long long
#define mm0(a) memset(a,0,sizeof(a))
#define mm(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxe=1e6+5;
const int maxn=1e3+5;
const double Inf=1e18;
struct Edge{
    int to, next;
    double dist;
    Edge(){}
    Edge(int a,int b,double c):to(a), next(b), dist(c){}
};
int n, ecnt;
Edge edges[maxe];
double x[maxn], y[maxn];
int W[maxn], head[maxn], intree[2*maxe], costfrom[maxn], vis[maxn];
double maxcost[maxn][maxn];
double lowcost[maxn];
vector<int> nodes;
void Init(int n){
    ecnt=0;
    mm(head,-1);
    mm0(intree);
    mm0(vis);
    for(int i=0;i<n;i++)
    for(int j=0;j<n;j++)
    maxcost[i][j]=0;
}
double dis(int a,int b){
    return sqrt((x[a]-x[b])*(x[a]-x[b])+(y[a]-y[b])*(y[a]-y[b]));
}
void Add_Edge(int u,int v,double d){
    edges[ecnt]=Edge(v,head[u],d);
    head[u]=ecnt++;
}
double Prim(){
    double sum=0;
    for(int i=0;i<n;i++){
        lowcost[i]=Inf;
        vis[i]=0;
    }
    for(int i=head[0];i!=-1;i=edges[i].next){
        Edge &e=edges[i];
        lowcost[e.to]=e.dist;
        costfrom[e.to]=i;
    }
    vis[0]=1;
    while(1){
        int u=n;
        lowcost[u]=Inf;
        for(int i=0;i<n;i++)
        if(!vis[i]&&lowcost[i]<lowcost[u])
            u=i;
        if(u==n) break;
        vis[u]=1;
        sum+=lowcost[u];
        intree[costfrom[u]]=1;
        intree[costfrom[u]^1]=1;
        for(int i=head[u];i!=-1;i=edges[i].next){
            Edge &e=edges[i];
            if(lowcost[e.to]>e.dist){
                lowcost[e.to]=e.dist;
                costfrom[e.to]=i;
            }
        }
    }
    return sum;
}
void Dfs(int u,int fa,double cost){
    for(int i=0;i<nodes.size();i++){
        int x=nodes[i];
        maxcost[u][x]=maxcost[x][u]=max(maxcost[x][fa],cost);
    }
    nodes.push_back(u);
    for(int i=head[u];i!=-1;i=edges[i].next)
    if(intree[i]){
        Edge &e=edges[i];
        if(e.to==fa) continue;
        Dfs(e.to, u, e.dist);
    }
}
void solve(){
    double sum=Prim();
    nodes.clear();
    Dfs(0,-1,0);
    double ans=0;
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++)
    ans=max(ans,(W[i]+W[j])*1.0/(sum-maxcost[i][j]));
    printf("%.2lf\n",ans);
}
int main(){

//      freopen("matrix.in","r",stdin);//从in.txt中读取数据
//      freopen("matrix.out","w",stdout);//输出到out.txt文件
    int T;

    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        Init(n);
        for(int i=0;i<n;i++){
            scanf("%lf%lf%d",&x[i],&y[i],&W[i]);
        }
        for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++){
            Add_Edge(i,j,dis(i,j));
            Add_Edge(j,i,dis(i,j));
        }
        solve();
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值