UVA - 1279 Asteroid Rangers

题意,有n个匀速动点,求最小生成树的改变次数。

先求出最开始的最小生成树,当MST中的某条线段v长度被不在MST的线段u取代的时候,最小生成树才会发生变化,

具体来说,已经知道之前的MST,边按照长度排序,在这个时间点之前的瞬间,v一定是MST最长的边,u紧跟在v之后,在这个时间点之后u和v的位置交换了一下,

根据Kruskal算法,对于u和v之前的边没有影响,前面的边连完以后如果u的两个端点不在同一个连通分量里,那么u会被加入形成新的MST,否则MST不变。

根据边长的平方对时间的函数求出所有线段u和v长度相等且之后u更短的时间点,按照时间顺序排序,一旦满足上述条件,就修改MST。

为了维护MST需要维护一个MST到边的映射,为了判断新线段在不在MST中以及忽略旧边需要维护一个边到MST编号的映射。

求时间点时有解的三种情况:

一开始先对线段长度排过序,所以保证Lj>Li,

第一种情况是a=0,一个解,之后j更短。

第二种情况是a<0,因为Lj>Li,所以只有大的那个是合法的,之后j更短。

第三种情况,a>0,第一个解是j更短,第二个解是i更短。

7发才过,太难了

#include<bits/stdc++.h>
using namespace std;

const double eps = 1e-8;

struct Event
{
    double t;
    int u,v; //这个时间点以后u更短
    bool operator < (const Event& r) const {
        return t < r.t;
    }
};

vector<Event> events;
#define PB push_back
const int maxn = 51;
const int maxl = maxn*(maxn-1)>>1;

struct Point
{
    double x,y,z,dx,dy,dz;
    void read(){ scanf("%lf%lf%lf%lf%lf%lf",&x,&y,&z,&dx,&dy,&dz); }
    Point operator - (const Point&r) { return {x-r.x, y-r.y, z-r.z, dx-r.dx, dy-r.dy, dz-r.dz}; }
}P[maxn];

#define squ(x)  ((x)*(x))

struct Seg
{
    double a,b,c;
    int u,v;
    void cal(int i,int j){
        u = i; v = j;
        Point t = P[i]-P[j];
        a = squ(t.dx) + squ(t.dy) + squ(t.dz);
        b = 2*(t.dx*t.x + t.dy*t.y + t.dz*t.z);
        c = squ(t.x) + squ(t.y) + squ(t.z);
    }
}L[maxl];

bool operator < (const Seg&x, const Seg&y) { return x.c < y.c; }

int lcnt;
int n;

//if equation has two roots, r1 < r2
int solveEqu(double a,double b,double c,double &r1,double &r2)
{
    if(fabs(a)<eps){
        if(fabs(b)<eps) return 0;
        r1 = -c/b;
        return 1;
    }
    double delta = b*b-4.*a*c;
    if(delta<eps) return 0;
    delta = sqrt(delta);
    if(a>0){
        r1 = (-b-delta)/(2.*a);
        r2 = (-b+delta)/(2.*a);
    }else {
        r1 = (-b+delta)/(2.*a);
        r2 = (-b-delta)/(2.*a);
    }
    return 2;
}

int pa[maxl];

int pos[maxl]; //map: Edge  to MST
int e[maxn]; //map: MST to Edge

void initUFS() { for(int i = 0; i < n; i++) pa[i] = i; }
int Find(int x) { return x == pa[x]?x:pa[x]=Find(pa[x]); }

int main()
{
    //freopen("in.txt","r",stdin);
    int kas = 0;
    while(~scanf("%d",&n)){
        for(int i = 0; i < n; i++) P[i].read();
        events.clear(); lcnt = 0;
        for(int i = 0; i < n; i++){
            for(int j = i+1; j < n; j++){
                L[lcnt++].cal(i,j);
            }
        }
        sort(L,L+lcnt);//ascending order

        for(int i = 0; i < lcnt; i++){
            for(int j = i+1; j < lcnt; j++){
                double r[2];
                double a = L[j].a - L[i].a//j相对i的长度
                , b = L[j].b - L[i].b
                , c = L[j].c - L[i].c;

                int rcnt = solveEqu(a,b,c,r[0],r[1]);
                if(rcnt == 1){
                    if(r[0]>0) events.PB({r[0],j,i});
                }else if(rcnt == 2){
                    if(a<0){
                        if(r[1]>0) events.PB({r[1],j,i});
                    }else {
                        if(r[0]>0) events.PB({r[0],j,i});
                        if(r[1]>0) events.PB({r[1],i,j});
                    }

                }
            }
        }
        sort(events.begin(),events.end());
        //DeBugEv
        initUFS();
        memset(pos,0,sizeof(int)*lcnt);

        int idx = 0;
        for(int i = 0; i < lcnt; i++){
            int s1 = Find(L[i].u), s2 = Find(L[i].v);
            if(s1 != s2){
                pa[s1] = s2;
                e[pos[i] = ++idx] = i; //e[] 下标从1开始。0表不在MST中
                if(idx == n-1) break;
            }
        }

        int ans = 1;
        for(int i = 0; i < events.size(); i++){
            Event &ev = events[i];
            if(pos[ev.v]&&!pos[ev.u]){
                initUFS();
                int old = pos[ev.v];
                for(int j = 1; j <= idx; j++){
                    if(j == old) continue;
                    int s1 = Find(L[e[j]].u), s2 = Find(L[e[j]].v);
                    if(s1 != s2){ pa[s1] = s2; }
                }
                int s1 = Find(L[ev.u].u), s2 = Find(L[ev.u].v);
                if(s1 != s2){
                    ans++;
                    pos[ev.u] = old;
                    pos[ev.v] = 0;
                    e[old] = ev.u;
                }
            }
        }
        printf("Case %d: %d\n",++kas,ans);
    }
    return 0;
}
时间: 2024-10-29 13:19:53

UVA - 1279 Asteroid Rangers的相关文章

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

UVA 10341 Solve It

Problem F Solve It Input: standard input Output: standard output Time Limit: 1 second Memory Limit: 32 MB Solve the equation: p*e-x + q*sin(x) + r*cos(x) + s*tan(x) + t*x2 + u = 0 where 0 <= x <= 1. Input Input consists of multiple test cases and te

UVA 11014 - Make a Crystal(容斥原理)

UVA 11014 - Make a Crystal 题目链接 题意:给定一个NxNxN的正方体,求出最多能选几个整数点.使得随意两点PQ不会使PQO共线. 思路:利用容斥原理,设f(k)为点(x, y, z)三点都为k的倍数的点的个数(要扣掉一个原点O).那么全部点就是f(1),之后要去除掉共线的,就是扣掉f(2), f(3), f(5)..f(n).n为素数.由于这些素数中包括了合数的情况,而且这些点必定与f(1)除去这些点以外的点共线,所以扣掉.可是扣掉后会扣掉一些反复的.比方f(6)在f

[UVa] Palindromes(401)

UVA - 401 Palindromes Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description A regular palindrome is a string of numbers or letters that is the same forward as backward. For example, the string "ABCDED

uva 401.Palindromes

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=342 题目意思:给出一段字符串(大写字母+数字组成).判断是否为回文串 or 镜像串 or 回文镜像串 or 什么都不是.每个字母的镜像表格如下 Character Reverse Character Reverse Character Reverse A A M M Y Y B

[2016-02-19][UVA][129][Krypton Factor]

UVA - 129 Krypton Factor Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu Submit Status Description You have been employed by the organisers of a Super Krypton Factor Contest in which contestants have very high mental and physica

[2016-02-03][UVA][514][Rails]

时间:2016-02-03 22:24:52 星期三 题目编号:UVA 514 题目大意:给定若干的火车(编号1-n),按1-n的顺序进入车站, 给出火车出站的顺序,问是否有可能存在 分析:    FIFO,用栈模拟一遍即可, 方法:    根据输入的顺序,从1-n开始,当前操作的为i 如果i是当前对应的编号,那么直接跳过(进入B) 如果不是,根据当前需求的编号,小于i,就从栈顶弹出一个元素, 看这个元素是否是需求的,是则继续.否则NO 1 2 3 4 5 6 7 8 9 10 11 12 13

uva 11584 Partitioning by Palindromes 线性dp

// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串的数目 // // f[i] = min(f[i],f[j-1] + 1(j到i是回文串)) // // 这道题还是挺简单的,继续练 #include <algorithm> #include <bitset> #include <cassert> #include <

uva 10003 Cutting Sticks 简单区间dp

// uva 10003 Cutting Sticks 区间dp // 经典的区间dp // dp(i,j)表示切割小木棍i-j所需要的最小花费 // 则状态转移为dp(i,j) = min{dp(i,k) + dp(k,j) + a[j]-a[i]) // 其中k>i && k<j // a[j] - a[i] 为第一刀切割的代价 // a[0] = 0,a[n+1] = L; // dp数组初始化的时候dp[i][i+1]的值为 0,这表示 // 每一段都已经是切割了的,不