• UVA1279,Asteroid Rangers,星际游击队,好烦的最小生成树


    题意:
    三维空间内有n(n<=50)个点,每个点有初始坐标和xyz和xyz三个方向上的速度dxdydz
    求最小生成树变化的次数

    分析:
    最多啊n^2条边,最小生成树变化,无非是原来生成树中的某条边被新边替换
    所以对每两条边计算可能出现这两条边相等的时间,称之为一个Event,(n^4个)
    此时生成树可能会发生变化,对每个Event检查最小生成树有没有发生变化
    总复杂度n^6,会炸
    优化:对每个Event看这个时间点的两条相等的边(一条上升趋势A一条下降趋势B)
    如果A在当前的生成树里面,则重新搞出生成树复杂度n^2,
    这样可以减少切换次数,可以卡过去(lrj的分析= =)

    流程:
    首先读进去点,每个点6个参数,构造边Edges,//makeEdges
    然后构造Events事件时间点,sort//makeEvents
    构造初始状态的最小生成树//work
    对每个时间点如果当前生成树上有边是此时的oldEdge,//work
    则更新生成树//EndWork

    代码有点长,有点烦,结构体多不要嫌烦,

    #include<cstdio>
    #include<cmath>
    #include<vector>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N = 9999;
    const double EPS = 1e-6;
    int n;
    struct point{
        double x,y,z,dx,dy,dz;
        inline void read(){
            scanf("%lf%lf%lf%lf%lf%lf",&x,&y,&z,&dx,&dy,&dz);
        }
    }po[N];
    
    struct Edge{
        double a,b,c;
        int from,to;
        bool operator < (const Edge &a)const{
            return c < a.c;
        }
    }edges[N];
    int E;
    inline double sqr(double x){return x*x;}
    inline void makeEdges(){
        E = 0;
        for (int i=1; i<n; i++){
            for (int j=i+1;j<=n;j++){
                edges[++E].a = sqr(po[i].dx - po[j].dx)
                             + sqr(po[i].dy - po[j].dy)
                             + sqr(po[i].dz - po[j].dz);
                edges[E].b = 2*( (po[i].dx - po[j].dx)*(po[i].x - po[j].x)
                                +(po[i].dy - po[j].dy)*(po[i].y - po[j].y)
                                +(po[i].dz - po[j].dz)*(po[i].z - po[j].z));
                edges[E].c = sqr(po[i].x - po[j].x)
                           + sqr(po[i].y - po[j].y)
                           + sqr(po[i].z - po[j].z);
                edges[E].from = i;
                edges[E].to = j;
            }
        }
        sort(edges + 1,edges + E + 1);
    }
    
    struct Event{
        double t;//time
        int newE, oldE;
        Event(double t=0,int n=0,int o=0):t(t),newE(n),oldE(o){}
        bool operator < (const Event &a) const {
            return t < a.t;
        }
    };
    vector <Event> events;
    inline void makeEvents(){
        events.clear();
        for (int i=1; i<E; i++){
            for (int j=i+1;j<=E;j++){
                int s1 = i, s2 = j;
                if (edges[s1].a < edges[s2].a) swap(s1,s2);//*****
                double a = edges[s1].a - edges[s2].a;
                double b = edges[s1].b - edges[s2].b;
                double c = edges[s1].c - edges[s2].c;
                if (fabs(a) < EPS){//b*t + c = 0
                    if (fabs(b) < EPS) continue;
                    if (b>0){swap(s1,s2);b=-b;c=-c;}
                    if (c>0) events.push_back(Event(-c/b,s1,s2));
                }else {
                    double delta = b*b - 4*a*c;
                    if (delta<EPS) continue;//no solution
                    delta = sqrt(delta);
                    double t1 = (-b-delta)/(2*a);
                    double t2 = (-b+delta)/(2*a);
                    if (t1>0)events.push_back(Event(t1,s1,s2));
                    if (t2>0)events.push_back(Event(t2,s2,s1));
                }
            }
        }
        sort(events.begin(),events.end());
    }
    
    int f[N], pos[N], e[N];
    int F(int x){return f[x]==x?x:f[x]=F(f[x]);}
    inline int work(){
        for (int i=0;i<=n;i++)f[i]=i;
        memset(pos, 0, sizeof(pos));
        int cnt = 0;
        for (int i=1;i<=E;i++){//kruskal
            int x = F(edges[i].from);
            int y = F(edges[i].to  );
            if (x==y) continue;
            //printf("edge:%d-%d
    ",edges[i].from,edges[i].to);
            f[x] = y;
            e[pos[i]=++cnt] = i;
            if (cnt==n-1)break;
        }
    
        int ans = 1;
        for (int i=0;i<events.size();i++){
            if (!pos[events[i].oldE]) continue;
            if ( pos[events[i].newE]) continue;
            for (int i=0; i<=n; i++) f[i] = i ;
            int oldPos = pos[events[i].oldE];
            for (int j = 1;j<n;j++){
                if (j==oldPos)continue;
                int x = F(edges[e[j]].from);
                int y = F(edges[e[j]].to  );
                if (x != y) f[x] = y;
            }
            int x = F(edges[events[i].newE].from);
            int y = F(edges[events[i].newE].to  );
            if (x == y) continue;
            ans ++;
            pos[events[i].newE] = oldPos;
            e[oldPos] = events[i].newE;
            pos[events[i].oldE] = 0;
        }
        return ans;
    }
    
    int main(){
        //freopen("in.txt","r",stdin);
        for (int cas=0;~scanf("%d",&n);){
            for (int i=1;i<=n;i++)po[i].read();
            makeEdges();
            makeEvents();
            int ans = work();
            printf("Case %d: %d
    ",++cas,ans);
        }
        return 0;
    }
    

    这里写图片描述

  • 相关阅读:
    SQL Server 创建用户报错:消息 15023,级别 16,状态 1,第 1 行 用户、组或角色 'XXX' 在当前数据库中已存在。
    Win10安装sqlserver2014打开显示黑色界面,mardown打开显示报错
    Centos7磁盘超过2TB使用parted命令分区
    Html5學習重點清單
    jQuery源码学习扒一扒jQuery对象初使化
    jQuery源码学习
    算法排序之插入排序
    算法排序之冒泡排序
    Sublime Text 3 安装
    css布局你该了解的
  • 原文地址:https://www.cnblogs.com/cww97/p/7533963.html
Copyright © 2020-2023  润新知