题意:
有n个城市,秦始皇要修用n-1条路把它们连起来,要求从任一点出发,都可以到达其它的任意点。秦始皇希望这所有n-1条路长度之和最短。然后徐福突然有冒出来,说是他有魔法,可以不用人力、财力就变出其中任意一条路出来。
秦始皇希望徐福能把要修的n-1条路中最长的那条变出来,但是徐福希望能把要求的人力数量最多的那条变出来。对于每条路所需要的人力,是指这条路连接的两个城市的人数之和。
最终,秦始皇给出了一个公式,A/B,A是指要徐福用魔法变出的那条路所需人力, B是指除了徐福变出来的那条之外的所有n-2条路径长度之和,选使得A/B值最大的那条。
题解:
次小生成树稍微改一下,因为要让A/B最大,肯定要枚举每条边找到最优,当加入的边是最小生成树外的就-path[i][j],如果是树内的就-map[i][j]即可。麻痹,这道题有一个点坑了我一上午,就是在枚举次小生成树的时候i不能等于j,为什么?如果会出现最大的人口的点相加两次再去除的,这样是不对的!过了这样点之后终于看到绿色了。。。。。也学到了原来INF*1.0就可以转化成double。
//有点挫的代码
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int MAXN=1005;
struct node
{
double x,y,w;
}a[MAXN];
double map[MAXN][MAXN];
double dis[MAXN];
double path[MAXN][MAXN];
int pre[MAXN];
int stack[MAXN];
bool vis[MAXN];
int n,cnt;
double prim()
{
double sum=0;
memset(vis,false,sizeof(vis));
memset(pre,0,sizeof(pre));
memset(stack,0,sizeof(stack));
for(int i=1;i<=n;i++)
dis[i]=map[1][i],pre[i]=1;
vis[1]=true;
stack[cnt++]=1;
for(int i=1;i<=n;i++)
{
double MIN=1000000000;
int k=0;
for(int j=1;j<=n;j++)
if(!vis[j]&&dis[j]<MIN)
MIN=dis[j],k=j;
vis[k]=true;
for(int j=0;j<cnt;j++)
path[stack[j]][k]=path[k][stack[j]]=max(path[stack[j]][pre[k]],MIN);
stack[cnt++]=k;
for(int j=1;j<=n;j++)
if(!vis[j]&&map[k][j]<dis[j]){
dis[j]=map[k][j];
pre[j]=k;
}
}
for(int i=1;i<=n;i++) sum+=dis[i];
return sum;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cnt=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].w);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
map[i][j]=0;
else
map[i][j]=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
}
double mst=prim();
double ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
continue;
if(i!=pre[j]&&j!=pre[i])
ans=max(ans,(a[i].w+a[j].w)/(mst-path[i][j]));
else
ans=max(ans,(a[i].w+a[j].w)/(mst-map[i][j]));
}
printf("%0.2lf\n",ans);
}
}
//这个代码好用一点,时间也快点
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int MAXN=1005;
struct node
{
double x,y,w;
}a[MAXN];
double map[MAXN][MAXN];
double path[MAXN][MAXN];
double dis[MAXN];
int pre[MAXN];
bool vis[MAXN];
bool used[MAXN][MAXN];
int n;
double prim()
{
double sum=0;
memset(pre,0,sizeof(pre));
memset(vis,false,sizeof(vis));
memset(path,0,sizeof(path));
memset(used,false,sizeof(used));
for(int i=1;i<=n;i++)
dis[i]=map[1][i],pre[i]=1;
vis[1]=true;
for(int i=1;i<=n;i++)
{
double MIN=INF*1.0;
int k=0;
for(int j=1;j<=n;j++)
if(!vis[j]&&MIN>dis[j])
MIN=dis[j],k=j;
vis[k]=true;
used[k][pre[k]]=used[pre[k]][k]=true;
for(int j=1;j<=n;j++)
{
if(vis[j]&&j!=k)//这里一定要有j!=k,如果两者相等的话,path[j][pre[j]]与MIN比较,从而导致path[i][i]不等于0的。导致破坏了最优状态
path[k][j]=path[j][k]=max(path[j][pre[k]],MIN);
if(!vis[j]&&map[k][j]<dis[j])
dis[j]=map[k][j],pre[j]=k;
}
}
for(int i=1;i<=n;i++) sum+=dis[i];
return sum;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf%lf%lf",&a[i].x,&a[i].y,&a[i].w);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j)
map[i][j]=0;
else
map[i][j]=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y));
double mst=prim();
double ans=-1;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
continue;
if(!used[i][j])
ans=max(ans,(a[i].w+a[j].w)/(mst-path[i][j]));
else
ans=max(ans,(a[i].w+a[j].w)/(mst-map[i][j]));
}
printf("%.2lf\n",ans);
}
}