[bsoj1922] 机器蛇


题目描述

  在未来的某次战争中,我军计划了一次军事行动,目的是劫持敌人的航母。由于这个计划高度保密,你只知道你所负责的一部分:机器蛇的通信网络。计划中要将数百条机器蛇投放到航母的各个角落里。由于航母内部舱室、管线错综复杂,且大部分由金属构成,因此屏蔽效应十分强烈,况且还要考虑敌人的大强度电子干扰,如何保持机器蛇间的联系,成了一大难题。每条机器蛇的战斗位置由作战计划部门制定,将会及时通知你。每条机器蛇上都带有接收、发射系统,可以同时与多条机器蛇通讯。由于整个系统承载的数据量庞大,需要一个固定的通讯网络。情报部门提供了极其详尽的敌方航母图纸,使你对什么地方有屏蔽了如指掌。
  请你设计一个程序,根据以上信息构造通讯网络,要求信息可以在任意两条机器蛇间传递,同时为了避免干扰,通讯网络的总长度要尽可能的短。


输入格式

  第一行是一个整数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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值