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

一句话总结:动态问题的一般做法是先求出一个静态的解,然后求出解发生改变的事件,事件按照时间排序,依次处理。

先求出最开始的最小生成树(MST),当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更短。

#include<bits/stdc++.h>
using namespace std; const double eps = 1e-; 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 = ;
const int maxl = maxn*(maxn-)>>; 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 = *(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 ;
r1 = -c/b;
return ;
}
double delta = b*b-.*a*c;
if(delta<eps) return ;
delta = sqrt(delta);
if(a>){
r1 = (-b-delta)/(.*a);
r2 = (-b+delta)/(.*a);
}else {
r1 = (-b+delta)/(.*a);
r2 = (-b-delta)/(.*a);
}
return ;
} int pa[maxl]; int pos[maxl]; //map: Edge to MST
int e[maxn]; //map: MST to Edge void initUFS() { for(int i = ; 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 = ;
while(~scanf("%d",&n)){
for(int i = ; i < n; i++) P[i].read();
events.clear(); lcnt = ;
for(int i = ; i < n; i++){
for(int j = i+; j < n; j++){
L[lcnt++].cal(i,j);
}
}
sort(L,L+lcnt);//ascending order for(int i = ; i < lcnt; i++){
for(int j = i+; j < lcnt; j++){
double r[];
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[],r[]);
if(rcnt == ){
if(r[]>) events.PB({r[],j,i});
}else if(rcnt == ){
if(a<){
if(r[]>) events.PB({r[],j,i});
}else {
if(r[]>) events.PB({r[],j,i});
if(r[]>) events.PB({r[],i,j});
} }
}
}
sort(events.begin(),events.end());
//DeBugEv
initUFS();
memset(pos,,sizeof(int)*lcnt); int idx = ;
for(int i = ; 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-) break;
}
} int ans = ;
for(int i = ; i < events.size(); i++){
Event &ev = events[i];
if(pos[ev.v]&&!pos[ev.u]){
initUFS();
int old = pos[ev.v];
for(int j = ; 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] = ;
e[old] = ev.u;
}
}
}
printf("Case %d: %d\n",++kas,ans);
}
return ;
}

UVA - 1279 Asteroid Rangers (动点的最小生成树)的更多相关文章

  1. 紫书 例题 11-14 UVa 1279 (动点最小生成树)(详细解释)

    这道题写了好久-- 在三维空间里面有动的点, 然后求有几次最小生成树. 其实很容易发现, 在最小生成树切换的时候,在这个时候一定有两条边相等, 而且等一下更大的那条边在最小生成树中,等一下更小的边不在 ...

  2. UVA 1151 Buy or Build (MST最小生成树,kruscal,变形)

    题意: 要使n个点之间能够互通,要使两点直接互通需要耗费它们之间的欧几里得距离的平方大小的花费,这说明每两个点都可以使其互通.接着有q个套餐可以选,一旦选了这些套餐,他们所包含的点自动就连起来了,所需 ...

  3. UVA:11183:Teen Girl Squad (有向图的最小生成树)

    Teen Girl Squad Description: You are part of a group of n teenage girls armed with cellphones. You h ...

  4. 【uva 1395】Slim Span(图论--最小生成树+结构体快速赋值 模版题)

    题意:给一个N(N<=100)个点的联通图(无自环和平行边),求苗条度(最大边-最小边的值)尽量小的生成树. 解法:枚举+Kruskal.先从小到大排序边,枚举选择的最小的边. 1 #inclu ...

  5. UVALive 4080 Warfare And Logistics (最短路树)

    很多的边会被删掉,需要排除一些干扰进行优化. 和UVA - 1279 Asteroid Rangers类似,本题最关键的地方在于,对于一个单源的最短路径来说,如果最短路树上的边没有改变的话,那么最短路 ...

  6. 训练指南 UVA- 11865(有向最小生成树 + 朱刘算法 + 二分)

    layout: post title: 训练指南 UVA- 11865(有向最小生成树 + 朱刘算法 + 二分) author: "luowentaoaa" catalog: tr ...

  7. 关于最小生成树 Kruskal 和 Prim 的简述(图论)

    模版题为[poj 1287]Networking. 题意我就不说了,我就想简单讲一下Kruskal和Prim算法.卡Kruskal的题似乎几乎为0.(●-`o´-)ノ 假设有一个N个点的连通图,有M条 ...

  8. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  9. 基尔霍夫矩阵题目泛做(AD第二轮)

    题目1: SPOJ 2832 题目大意: 求一个矩阵行列式模一个数P后的值.p不一定是质数. 算法讨论: 因为有除法而且p不一定是质数,不一定有逆元,所以我们用辗转相除法. #include < ...

随机推荐

  1. 招聘.Net中高级软件研发工程师

    岗位职责: 1.参与国土不动产系列软件需求分析.系统架构分析与设计: 2.为产品中的复杂功能编写产品开发需求文档: 3.根据设计文档或需求说明完成代码编写.调试.测试和维护: 4.配合上级进行技术决策 ...

  2. python数据分析笔记中panda(2)

    1 将手机号码分开为运营商,地区和号码段 from pandas import read_csv; df = read_csv("H:\\pythonCode\\4.6\\data.csv& ...

  3. HDU1059 【DP·二进制数优化】

    题意: 有6种不同价值的物品,然后问你能不能分成两半使得两堆价值相等: 思路: 一共有20000*6=120000 多的价值, 总共背包有20000个,价值最大是120000,看看能不能DP到valu ...

  4. lightoj 1125【背包·从n个选m个】

    题意: 给你 n 个背包,然后给你两个数,D,M,问你从n个里面挑M个出来,有多少种方法能够整除D: 思路: 试想我先不挑M个出来的话,仅仅是构造一个D的倍数,其实就是构造一个数的话, 其实就是个递推 ...

  5. Unity2016 Unity3D开发VR游戏的经验

    http://z.youxiputao.com/articles/8313 在4月12日的Unite 2016大会上,暴风魔镜高级产品经理吴涛分享他用Unity3D开发VR游戏的经验,以下为分享实录: ...

  6. [Xcode 实际操作]九、实用进阶-(31)为IAP(支付方式)内购功能的具体实现和测试

    目录:[Swift]Xcode实际操作 本文将演示如何为IAP(支付方式)内购功能的具体实现和测试. 内购是苹果市场上的一种常见的盈利方式. 在项目中确保已经安装了第三方库[Pod],双击[Podfi ...

  7. XHTML学习笔记 part1

    XHTML: 可扩展超文本标记语言 HTML语言最开始是用来描述文档的结构,如标题,段落等标记,后来HTML有增加了一些控制字体,对齐等方面的标记和属性,这样做的结果是HTML既可以用来描述文档的结构 ...

  8. E.华华给月月准备礼物

    链接:https://ac.nowcoder.com/acm/contest/392/E 题意: 二月中旬虐狗节前夕,华华决定给月月准备一份礼物.为了搭建礼物的底座,华华需要若干根同样长的木棍.华华手 ...

  9. Unity Shader入门精要学习笔记 - 第14章非真实感渲染

    转载自 冯乐乐的 <Unity Shader 入门精要> 尽管游戏渲染一般都是以照相写实主义作为主要目标,但也有许多游戏使用了非真实感渲染(NPR)的方法来渲染游戏画面.非真实感渲染的一个 ...

  10. Spring之WebContext不使用web.xml启动 初始化重要的类源码分析(Servlet3.0以上的)

    入口: org.springframework.web.SpringServletContainerInitializer implements ServletContainerInitializer ...