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

来源:互联网 发布:银行it外包 编辑:程序博客网 时间:2024/04/30 03:40

题意:
三维空间内有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\n",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\n",++cas,ans);    }    return 0;}

这里写图片描述

0 0