这道题我一开始的想法就是对的,记录任意两点路径上的最大边权,然后枚举两点,找到A/B的最大值。
关键是这个记录真不好记录,想来想去没什么想法,代码能力还是太弱了,想到了先生成树再来记录什么的,
觉得复杂度好高,还是觉得PRIM在加边的过程中就直接记录了,想了很久,后来才想通,开一个一维数组记录
它的父节点再开一个二维数组记录DP[I][J],I->J的路径上的最大边权,每加入一点,就在已经VISIT的集合里算
出所有的与这点路径上的最大边权,其实每次只要比较一次就好了,这个点到其父亲节点的距离,父亲节点与其他点的长度
选一个最大的就好了,因为在这个点加入之前,其父亲节点必然已经更新过了!
代码还未写注释,下次吧。。
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
#define inf 0x7fffffff
#define eps 1e-8
#define maxn 1100
using namespace std;
double graph[maxn][maxn];
int pre[maxn];
double dp[maxn][maxn];
double dist[maxn];
int vis[maxn];
int n;
double ans;
struct point
{
double x,y;
int peo;
}p[maxn];
struct edge
{
int u,v;
double len;
}a[maxn*maxn];
double dis(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double Max(double a,double b)
{
return a>b?a:b;
}
double prim()
{
int i,j,k;
double sum=0.0;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
{
dist[i]=graph[1][i];
pre[i]=1;
dp[i][i]=0.0;
}
vis[1]=1;
for(i=2;i<=n;i++)
{
double t=inf*1.0;
for(j=1;j<=n;j++)
{
if(!vis[j]&&dist[j]<t)
{
t=dist[j];
k=j;
}
}
int fa=pre[k];
dp[fa][k]=dp[k][fa]=graph[fa][k];
sum+=t;
for(j=1;j<=n;j++)
{
if(vis[j])
{
dp[j][k]=dp[k][j]=Max(dp[j][fa],dp[fa][k]);
}
}
vis[k]=1;
for(j=1;j<=n;j++)
{
if(!vis[j]&&dist[j]>graph[k][j])
{
pre[j]=k;
dist[j]=graph[k][j];
}
}
}
return sum;
}
void solve(double res)
{
int i,j;
ans=0.0;
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
double mi=(p[i].peo+p[j].peo)*1.0/(res-dp[i][j]);
if(mi>ans)
ans=mi;
}
}
}
int main()
{
//freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--)
{
int i,j;
memset(graph,0,sizeof(graph));
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%lf%lf%d",&p[i].x,&p[i].y,&p[i].peo);
}
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
{
graph[i][j]=graph[j][i]=dis(p[i].x,p[i].y,p[j].x,p[j].y);
dp[i][j]=dp[j][i]=0;
}
}
double res=prim();
//printf("%.2lf\n",res);
solve(res);
printf("%.2lf\n",ans);
}
return 0;
}