UVA1279星际游击队推导过程

来源:互联网 发布:天刀捏脸数据女 2016 编辑:程序博客网 时间:2024/04/27 13:23

参见lrj的思路:首先把两个点之间的边的函数化(可用一个带t的向量来表示边的变化),然后计算出每个时间点,即任意两条边的大小变成相同的时刻,可用一个结构体来存储。。

最后,计算最初的最小生成树,把存储的事件都拿出来进行比较,符合条件的话,ans++。


思路貌似很简单,网上也有该题的代码,可是如何推出两点之间的边的函数呢?其实也很简单。。


设三个动点的坐标为(x1+dx1*t,y1+dy1*t,z1+dz1*t),(x2+dx2*t,y2+dy2*t,z2+dz2*t),(x3+dx3*t,y3*dy3*t,z3*dz3*t)。

这三个点可组成3个边,可任意算出两条边的向量,(x1-x2+(dx1-dx2)*t,y1-y2+(dy1-dy2)*t,z1-z2+(dz1-dz2)*t)和(x1-x3+(dx1-dx3)*t,y1-y3+(dy1-dy3)*t,z1-z3+(dz1-dz3)*t)


ok,,取这两条向量的模,写出等式.. 

(x1-x2+(dx1-dx2)*t)^2+(y1-y2+(dy1-dy2)*t)^2+(z1-z2+(dz1-dz2)*t)^2=(x1-x3+(dx1-dx3)*t)^2+(y1-y3+(dy1-dy3)*t)^2+(z1-z3+(dz1-dz3)*t)^2

可以发现,化简得出的函数是关于t的一个2次函数,点的坐标我们都知道,所以可以求出t,然后判断t是否大于0,想一下,我们可以在存边的时候将该函数的t的2次方系数和t的1次方系数和常数存起来,然后在计算事件点的时候拿出来计算。


接下来就是高中的数学题了,例如at^2+bt+c=0,先分类a是否为0,然后分类b和c什么情况下可得出大于0的解,高中知识,这里不再详述..(然而我就是因为这里wa了一个下午..)


接下来就是代码..

#include<iostream>#include<vector>#include<algorithm>#include<math.h>#include<cstring>using namespace std;#pragma warning (disable:4996)const int N = 9999;const double EPS = 1e-6;int n;int E;struct node{double x, y, z, dx, dy, dz;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&b)const{return c < b.c;}}edges[N];#pragma region eventstruct Event{int newE, oldE;double t;Event(int a=0, int b=0, double _t=0) : newE(a), oldE(b), t(_t) {}bool operator<(const Event&b)const{return t < b.t;}};vector<Event>events;#pragma endregiondouble sqr(double x) { return x*x; }void makeedge(){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].x - po[j].x)*(po[i].dx - po[j].dx) + (po[i].y - po[j].y)*(po[i].dy - po[j].dy) + (po[i].z - po[j].z)*(po[i].dz - po[j].dz));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;//E++;}sort(edges + 1, edges + 1 + E);}void makeevent(){for (int i = 1;i<E;i++)for (int j = i + 1;j <= E;j++){Edge s1 = edges[i];Edge s2 = edges[j];int ss1 = i, ss2 = j;if (s1.a < s2.a)swap(s1, s2),swap(ss1,ss2);double a = s1.a - s2.a;double b = s1.b - s2.b;double c = s1.c - s2.c;if (fabs(a) <EPS){if (fabs(b) < EPS)continue;if (b > 0) { swap(ss1, ss2); b = -b;c = -c; }if (c > 0)events.push_back(Event(ss1,ss2,-c/b));}else{double check = b*b - 4 * a*c;if (check < EPS)continue;double cc = sqrt(check);double t1 = (-b - cc) / (2 * a);double t2 = (-b + cc) / (2 * a);if (t1 > 0)events.push_back(Event(ss1, ss2, t1));if (t2 > 0)events.push_back(Event(ss2, ss1, t2));}}sort(events.begin(), events.end());}void init(){events.clear();E = 0;}int p[55];int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }int solve(){//int ans = 0;int cnt = 0;int pos[9999];int e[9999];memset(pos, 0, sizeof(pos));for (int i = 0;i <= n;i++)p[i] = i;for (int i = 1;i <= E;i++){int x = find(edges[i].from);int y = find(edges[i].to);if (x == y)continue;p[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].newE])continue;if (!pos[events[i].oldE])continue;for (int i = 0;i <= n;i++)p[i] = i;int oldpos = pos[events[i].oldE];for (int j = 1;j < n;j++){if (j != oldpos){int x = find(edges[e[j]].from);int y = find(edges[e[j]].to);if (x != y)p[x] = y;}}int x = find(edges[events[i].newE].from);int y = find(edges[events[i].newE].to);if (x == y)continue;ans++;//int thenum = pos[events[i].oldE];pos[events[i].newE] = oldpos;e[oldpos] = events[i].newE;pos[events[i].oldE] = 0;}return ans;}int main(){int kase = 1;while (cin >> n){init();for (int i = 1;i <= n;i++)po[i].read();printf("Case %d: ", kase++);makeedge();makeevent();printf("%d\n", solve());}return 0;}

原创粉丝点击