题目描述
在未来的某次战争中,我军计划了一次军事行动,目的是劫持敌人的航母。由于这个计划高度保密,你只知道你所负责的一部分:机器蛇的通信网络。计划中要将数百条机器蛇投放到航母的各个角落里。由于航母内部舱室、管线错综复杂,且大部分由金属构成,因此屏蔽效应十分强烈,况且还要考虑敌人的大强度电子干扰,如何保持机器蛇间的联系,成了一大难题。每条机器蛇的战斗位置由作战计划部门制定,将会及时通知你。每条机器蛇上都带有接收、发射系统,可以同时与多条机器蛇通讯。由于整个系统承载的数据量庞大,需要一个固定的通讯网络。情报部门提供了极其详尽的敌方航母图纸,使你对什么地方有屏蔽了如指掌。
请你设计一个程序,根据以上信息构造通讯网络,要求信息可以在任意两条机器蛇间传递,同时为了避免干扰,通讯网络的总长度要尽可能的短。
输入格式
第一行是一个整数n(n≤200)表示参战的机器蛇总数。
以下n行,每行两个整数xi,yi,为第i支机器蛇的战斗位置。
接下来一行是一个整数m(m≤100)表示航母内部可能产生屏蔽的位置。
最后m行,每行四个整数ai,bi,ci,di,表示线段(ai,bi)-(ci,di)处可能有屏蔽,也就是说通讯网络不能跨越这条线段。
输出格式
仅一个实数,表示建立的通讯网的最短长度,保留3位小数。如果不能成功建立通讯网,请输出-1.000。
样例数据
样例输入
3
1 3
3 1
5 5
1
0 0 3 3
样例输出
8.944
题目分析
最小生成树
建边时用计算几何判断线段是否相交
源代码
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
struct Vector;
struct Point {
double x,y;
};
double Dist(Point a,Point b) {
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
struct Vector {
double x,y;
};
Vector operator - (Point a,Point b) {
Vector c;
c.x=b.x-a.x;
c.y=b.y-a.y;
return c;
}
double Cross(Vector a,Vector b) { //叉积
return a.x*b.y-b.x*a.y;
}
bool Segment_Intersect(Point A,Point B,Point C,Point D) { //判断两线段是否相交
return (Cross((C-A),(D-A))*Cross((C-B),(D-B))<0)&&(Cross((A-C),(B-C))*Cross((A-D),(B-D))<0);
}
const int maxn=50005;
struct Edge {
int x,y;
double v;
bool operator < (Edge b) const {
return v<b.v;
}
} a[maxn];
struct Kruskal {
int n,m,cnt;
double ans;
int father[maxn];
void init(int n,int m) {
this->n=n;
this->m=m;
ans=cnt=0;
}
void AddEdge(int from,int to,double dist) {
a[++cnt].x=from;
a[cnt].y=to;
a[cnt].v=dist;
}
int Get_Father(int x) {
if(father[x]==x)return x;
return father[x]=Get_Father(father[x]);
}
bool main() {
int cnt=0;
sort(a+1,a+m+1);
for(int i=1; i<=n; i++)father[i]=i;
for(int i=1; i<=m; i++) {
int f1=Get_Father(a[i].x),f2=Get_Father(a[i].y);
if(f1!=f2) {
father[f1]=f2;
ans+=a[i].v;
cnt++;
if(cnt==n-1)break;
}
}
if(cnt!=n-1)return false;
return true;
}
};
Point P[205],Start[205],End[205];
Kruskal krus;
int n,m,sum=0;
int main() {
n=Get_Int();
for(int i=1; i<=n; i++) {
P[i].x=Get_Int();
P[i].y=Get_Int();
}
m=Get_Int();
for(int i=1; i<=m; i++) {
Start[i].x=Get_Int();
Start[i].y=Get_Int();
End[i].x=Get_Int();
End[i].y=Get_Int();
}
for(int i=1; i<=n; i++)
for(int j=i+1; j<=n; j++) {
int bj=1;
for(int k=1; k<=m; k++)
if(Segment_Intersect(P[i],P[j],Start[k],End[k])) {
bj=0;
break;
}
if(bj==0)continue;
sum++;
krus.AddEdge(i,j,Dist(P[i],P[j]));
}
krus.init(n,sum);
if(!krus.main())puts("-1.000");
else printf("%0.3lf\n",krus.ans);
return 0;
}