洛谷 P1783 海滩防御(最小生成树)
传送门
解题思路
和上一道题基本相同。
但是这个题题面是真的复杂,读了好久才读懂。
关键在于如何建图。
将在第0列可以看做第0个点,第n列可以看做第m+1个点。
这两个特殊的点到其他点的距离为点线垂直距离,其他的点之间的距离为点点距。
还有不同的地方就是两个信号塔之间的距离是两个半径,而0点和m+1点到其他点的距离一个半径,建图时将其中一个除以2或者另一个乘2即可。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iomanip>
using namespace std;
const int maxn=1005;
int n,m,fa[maxn],cnt;
double ans;
struct node{
int u,v;
double w;
}e[maxn*maxn];
struct Node{
double x,y;
}a[maxn];
bool cmp(node a,node b){
return a.w<b.w;
}
int find(int x){
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
double getdis(int i,int j){
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))/2;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=0;i<=m+1;i++) fa[i]=i;
for(int i=1;i<=m;i++){
cin>>a[i].x>>a[i].y;
}
for(int i=1;i<=m;i++) {
e[++cnt].u=0;
e[cnt].v=i;
e[cnt].w=a[i].x;
e[++cnt].u=i;
e[cnt].v=m+1;
e[cnt].w=(n-a[i].x);
}
for(int i=1;i<m;i++){
for(int j=i+1;j<=m;j++){
e[++cnt].u=i;
e[cnt].v=j;
e[cnt].w=getdis(i,j);
}
}
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=cnt;i++){
ans=e[i].w;
int x=find(e[i].u),y=find(e[i].v);
if(x!=y){
fa[x]=y;
}
if(find(0)==find(m+1)) break;
}
cout<<fixed<<setprecision(2)<<ans;
return 0;
}