本题重点是对于第二条规则的理解:
如图,对于任意一点A,因为它申请修建AB道路,因此离A最近的点一定是B
同理,B申请修建BC道路,因此C一定比A离B更近(即C在圆B内,不包含边界)
同时,C申请修建CA道路,即A离C比A离B更近
满足题意的话,ABC只能组成正三角形,因此排除最短边有三种情况
因为题目有:
一个实数,四舍五入保留两位小数,表示公路总长。(保证有惟一解)
因此我们可以得出结论:
规则2是没有用的
于是,题目的第一条规则
如果两个或以上城市申请修建同一条公路,则让它们共同修建
明显是最小生成树,裸的板子
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++) if(!vis[j]&&dis[j]<MIN) MIN=dis[j],pos=j;
ans+=MIN; vis[pos]=1;MIN=oo;
for (int j=1;j<=n;j++) dis[j]=min(dis[j],Distance(pos,j));
}
再有,由于坐标范围很大,因此直接用函数求出距离即可
double Distance(int a,int b)
{return sqrt((double)(point[a].x-point[b].x)*(point[a].x-point[b].x)+
(double)(point[a].y-point[b].y)*(point[a].y-point[b].y));
}
于是就可以得出代码= =
#include<bits/stdc++.h>
#define oo 99999999
using namespace std;
int n,pos;
bool vis[5005];
double ans,MIN=oo,dis[5005];
struct tqr{int x,y;}point[5005];
double Distance(int a,int b){return sqrt((double)(point[a].x-point[b].x)*(point[a].x-point[b].x)+(double)(point[a].y-point[b].y)*(point[a].y-point[b].y));}
template<class T> inline void read(T &re){re=0;T sign=1;char tmp;while((tmp=getchar())&&(tmp<'0'||tmp>'9')) if(tmp=='-') sign=-1;re=tmp-'0';while((tmp=getchar())&&(tmp>='0'&&tmp<='9')) re=re*10+(tmp-'0');re*=sign;}
int main()
{
// freopen("road.in","r",stdin);
// freopen("road.out","w",stdout);
read(n);
for (int i=1;i<=n;i++){read(point[i].x);read(point[i].y);dis[i]=oo;}//读入和初始化
dis[1]=0;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++) if(!vis[j]&&dis[j]<MIN) MIN=dis[j],pos=j;
ans+=MIN; vis[pos]=1;MIN=oo;
for (int j=1;j<=n;j++) dis[j]=min(dis[j],Distance(pos,j));
}
printf("%.2lf\n",ans);
return 0;
}