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;
}