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;
}

这里写图片描述

原文地址:https://www.cnblogs.com/cww97/p/12349370.html