习题: Star Way To Heaven (最小生成树)
题目
思路
第一眼看到这道题的时候,
最开始想到的是二分&最小生成树
但是想想时间复杂度...\(O(log_{1e6}*k*k)\)
wtf???
但是
我们考虑什么时候才会最优
肯定是两个圆相切的时候才会最好
此时的值就是两个圆相切的距离除以2
所以。。。
我们只需要考虑两颗星星之间的距离,
再跑最小生成树算法即可,
但是如果是kruskal,这又是一个疏密图
总时间复杂度为\(O(log_{k*k}*k*k)\)
瞬间爆炸
所以这道题只能用prim算法
时间复杂度\(O(k*k)\)
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<climits>
using namespace std;
struct node
{
double x;
double y;
}a[6005];
int n,m,k;
bool vis[6005];
double dis[6005];
double solve_dis(int i,int j)
{
if(i>j)
swap(i,j);
if(i==0&&j==k)
return m;
if(i==0)
return a[j].y;
if(j==k)
return m-a[i].y;
return 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));
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=k;i++)
cin>>a[i].x>>a[i].y;
k++;
for(int i=1;i<=k;i++)
dis[i]=INT_MAX;
for(int i=1;i<=k;i++)
{
double minn=INT_MAX;
int u=-1;
for(int j=0;j<=k;j++)
{
if(dis[j]<minn&&!vis[j])
{
minn=dis[j];
u=j;
}
}
if(u==-1)
break;
vis[u]=1;
for(int v=1;v<=k;v++)
{
if(!vis[v])
{
dis[v]=min(dis[v],max(dis[u],solve_dis(u,v)));
}
}
}
printf("%.9lf",dis[k]/2);
return 0;
}