POJ 3845 Fractal(计算几何の旋转缩放)

Description

Fractals are really cool mathematical objects. They have a lot of interesting properties, often including: 
1. fine structure at arbitrarily small scales; 
2. self-similarity, i.e., magnified it looks like a copy of itself; 
3. a simple, recursive definition. 
Approximate fractals are found a lot in nature, for example, in structures such as clouds, snow flakes, mountain ranges, and river networks. 

In this problem, we consider fractals generated by the following algorithm: we start with a polyline, i.e., a set of connected line segments. This is what we call a fractal of depth one (see leftmost picture). To obtain a fractal of depth two, we replace each line segment with a scaled and rotated version of the original polyline (see middle picture). By repetitively replacing the line segments with the polyline, we obtain fractals of arbitrary depth and very fine structures arise. The rightmost picture shows a fractal of depth three. 
The complexity of an approximate fractal increases quickly as its depth increases. We want to know where we end up after traversing a certain fraction of its length.

Input

The input starts with a single number c (1 <= c <= 200) on one line, the number of test cases. Then each test case starts with one line with n (3 <= n <= 100), the number of points of the polyline. Then follow n lines with on the ith line two integers xi and yi ( -1 000 <= xi, yi <= 1 000), the consecutive points of the polyline. Next follows one line with an integer d (1 <= d <= 10), the depth of the fractal. Finally, there is one line with a floating point number f (0 <= f <= 1), the fraction of the length thatis traversed. 
The length of each line segment of the polyline is smaller than the distance between the first point (x1, y1) and the last point (xn, yn) of the polyline. The length of the complete polyline is smaller than twice this distance.

Output

Per test case, the output contains one line with the coordinate where we end up. Format it as (x,y), with two floating point numbers x and y. The absolute error in both coordinates should be smaller than 10-6.
 
题目大意:给一条折线,每一次操作把这条折线的所有线段变换成跟这条折线的相同形状,重复d次。问此时从头到尾走全长的f(0≤f≤1),将停在哪个点上。
思路:首先,设t = 这条折线的长度 / 头到尾的直线距离
那么这条线段变换成折线的时候,长度就会增大 t 倍
变换d次,长度就会增大 t^d 倍
那么,每一条线段变换后的长度都是可以直接求出来的,如果这条线段和之前的线段的长度加起来不到 全长 * f,就可以直接跳过
接下来就是缩放和旋转的细节,这些就不讲了,可以直接看代码,最下面分割线下的就是主要代码
为了代码简单化,几乎大部分都变成函数了
PS:这题虽然不难,但是花了大量的时间……最主要的原因是一开始看错题了……
 
代码(0MS):
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 using namespace std;
  7 
  8 const int MAXN = 110;
  9 const double EPS = 1e-8;
 10 const double PI = acos(-1.0);//3.14159265358979323846
 11 const double INF = 1;
 12 
 13 inline int sgn(double x) {
 14     return (x > EPS) - (x < -EPS);
 15 }
 16 
 17 struct Point {
 18     double x, y, ag;
 19     Point() {}
 20     Point(double x, double y): x(x), y(y) {}
 21     void read() {
 22         scanf("%lf%lf", &x, &y);
 23     }
 24     bool operator == (const Point &rhs) const {
 25         return sgn(x - rhs.x) == 0 && sgn(y - rhs.y) == 0;
 26     }
 27     bool operator < (const Point &rhs) const {
 28         if(y != rhs.y) return y < rhs.y;
 29         return x < rhs.x;
 30     }
 31     Point operator + (const Point &rhs) const {
 32         return Point(x + rhs.x, y + rhs.y);
 33     }
 34     Point operator - (const Point &rhs) const {
 35         return Point(x - rhs.x, y - rhs.y);
 36     }
 37     Point operator * (const double &b) const {
 38         return Point(x * b, y * b);
 39     }
 40     Point operator / (const double &b) const {
 41         return Point(x / b, y / b);
 42     }
 43     double length() {
 44         return sqrt(x * x + y * y);
 45     }
 46     Point unit() {
 47         return *this / length();
 48     }
 49     void print() {
 50         printf("%.10f %.10f\n", x, y);
 51     }
 52 };
 53 typedef Point Vector;
 54 
 55 double dist(const Point &a, const Point &b) {
 56     return (a - b).length();
 57 }
 58 
 59 double cross(const Point &a, const Point &b) {
 60     return a.x * b.y - a.y * b.x;
 61 }
 62 //ret >= 0 means turn left
 63 double cross(const Point &sp, const Point &ed, const Point &op) {
 64     return sgn(cross(sp - op, ed - op));
 65 }
 66 
 67 double area(const Point& a, const Point &b, const Point &c) {
 68     return fabs(cross(a - c, b - c)) / 2;
 69 }
 70 //counter-clockwise
 71 Point rotate(const Point &p, double angle, const Point &o = Point(0, 0)) {
 72     Point t = p - o;
 73     double x = t.x * cos(angle) - t.y * sin(angle);
 74     double y = t.y * cos(angle) + t.x * sin(angle);
 75     return Point(x, y) + o;
 76 }
 77 
 78 struct Seg {
 79     Point st, ed;
 80     double ag;
 81     Seg() {}
 82     Seg(Point st, Point ed): st(st), ed(ed) {}
 83     void read() {
 84         st.read(); ed.read();
 85     }
 86     void makeAg() {
 87         ag = atan2(ed.y - st.y, ed.x - st.x);
 88     }
 89 };
 90 typedef Seg Line;
 91 
 92 //ax + by + c > 0
 93 Line buildLine(double a, double b, double c) {
 94     if(sgn(a) == 0 && sgn(b) == 0) return Line(Point(sgn(c) > 0 ? -1 : 1, INF), Point(0, INF));
 95     if(sgn(a) == 0) return Line(Point(sgn(b), -c/b), Point(0, -c/b));
 96     if(sgn(b) == 0) return Line(Point(-c/a, 0), Point(-c/a, sgn(a)));
 97     if(b < 0) return Line(Point(0, -c/b), Point(1, -(a + c) / b));
 98     else return Line(Point(1, -(a + c) / b), Point(0, -c/b));
 99 }
100 
101 void moveRight(Line &v, double r) {
102     double dx = v.ed.x - v.st.x, dy = v.ed.y - v.st.y;
103     dx = dx / dist(v.st, v.ed) * r;
104     dy = dy / dist(v.st, v.ed) * r;
105     v.st.x += dy; v.ed.x += dy;
106     v.st.y -= dx; v.ed.y -= dx;
107 }
108 
109 bool isOnSeg(const Seg &s, const Point &p) {
110     return (p == s.st || p == s.ed) ||
111         (((p.x - s.st.x) * (p.x - s.ed.x) < 0 ||
112           (p.y - s.st.y) * (p.y - s.ed.y) < 0) &&
113          sgn(cross(s.ed, p, s.st) == 0));
114 }
115 
116 bool isIntersected(const Point &s1, const Point &e1, const Point &s2, const Point &e2) {
117     return (max(s1.x, e1.x) >= min(s2.x, e2.x)) &&
118         (max(s2.x, e2.x) >= min(s1.x, e1.x)) &&
119         (max(s1.y, e1.y) >= min(s2.y, e2.y)) &&
120         (max(s2.y, e2.y) >= min(s1.y, e1.y)) &&
121         (cross(s2, e1, s1) * cross(e1, e2, s1) >= 0) &&
122         (cross(s1, e2, s2) * cross(e2, e1, s2) >= 0);
123 }
124 
125 bool isIntersected(const Seg &a, const Seg &b) {
126     return isIntersected(a.st, a.ed, b.st, b.ed);
127 }
128 
129 bool isParallel(const Seg &a, const Seg &b) {
130     return sgn(cross(a.ed - a.st, b.ed - b.st)) == 0;
131 }
132 
133 //return Ax + By + C =0 's A, B, C
134 void Coefficient(const Line &L, double &A, double &B, double &C) {
135     A = L.ed.y - L.st.y;
136     B = L.st.x - L.ed.x;
137     C = L.ed.x * L.st.y - L.st.x * L.ed.y;
138 }
139 //point of intersection
140 Point operator * (const Line &a, const Line &b) {
141     double A1, B1, C1;
142     double A2, B2, C2;
143     Coefficient(a, A1, B1, C1);
144     Coefficient(b, A2, B2, C2);
145     Point I;
146     I.x = - (B2 * C1 - B1 * C2) / (A1 * B2 - A2 * B1);
147     I.y =   (A2 * C1 - A1 * C2) / (A1 * B2 - A2 * B1);
148     return I;
149 }
150 
151 bool isEqual(const Line &a, const Line &b) {
152     double A1, B1, C1;
153     double A2, B2, C2;
154     Coefficient(a, A1, B1, C1);
155     Coefficient(b, A2, B2, C2);
156     return sgn(A1 * B2 - A2 * B1) == 0 && sgn(A1 * C2 - A2 * C1) == 0 && sgn(B1 * C2 - B2 * C1) == 0;
157 }
158 
159 struct Poly {
160     int n;
161     Point p[MAXN];//p[n] = p[0]
162     void init(Point *pp, int nn) {
163         n = nn;
164         for(int i = 0; i < n; ++i) p[i] = pp[i];
165         p[n] = p[0];
166     }
167     double area() {
168         if(n < 3) return 0;
169         double s = p[0].y * (p[n - 1].x - p[1].x);
170         for(int i = 1; i < n; ++i)
171             s += p[i].y * (p[i - 1].x - p[i + 1].x);
172         return s / 2;
173     }
174 };
175 
176 void Graham_scan(Point *p, int n, int *stk, int &top) {//stk[0] = stk[top]
177     sort(p, p + n);
178     top = 1;
179     stk[0] = 0; stk[1] = 1;
180     for(int i = 2; i < n; ++i) {
181         while(top && cross(p[i], p[stk[top]], p[stk[top - 1]]) >= 0) --top;
182         stk[++top] = i;
183     }
184     int len = top;
185     stk[++top] = n - 2;
186     for(int i = n - 3; i >= 0; --i) {
187         while(top != len && cross(p[i], p[stk[top]], p[stk[top - 1]]) >= 0) --top;
188         stk[++top] = i;
189     }
190 }
191 //use for half_planes_cross
192 bool cmpAg(const Line &a, const Line &b) {
193     if(sgn(a.ag - b.ag) == 0)
194         return sgn(cross(b.ed, a.st, b.st)) < 0;
195     return a.ag < b.ag;
196 }
197 //clockwise, plane is on the right
198 bool half_planes_cross(Line *v, int vn, Poly &res, Line *deq) {
199     int i, n;
200     sort(v, v + vn, cmpAg);
201     for(i = n = 1; i < vn; ++i) {
202         if(sgn(v[i].ag - v[i-1].ag) == 0) continue;
203         v[n++] = v[i];
204     }
205     int head = 0, tail = 1;
206     deq[0] = v[0], deq[1] = v[1];
207     for(i = 2; i < n; ++i) {
208         if(isParallel(deq[tail - 1], deq[tail]) || isParallel(deq[head], deq[head + 1]))
209             return false;
210         while(head < tail && sgn(cross(v[i].ed, deq[tail - 1] * deq[tail], v[i].st)) > 0)
211             --tail;
212         while(head < tail && sgn(cross(v[i].ed, deq[head] * deq[head + 1], v[i].st)) > 0)
213             ++head;
214         deq[++tail] = v[i];
215     }
216     while(head < tail && sgn(cross(deq[head].ed, deq[tail - 1] * deq[tail], deq[head].st)) > 0)
217         --tail;
218     while(head < tail && sgn(cross(deq[tail].ed, deq[head] * deq[head + 1], deq[tail].st)) > 0)
219         ++head;
220     if(tail <= head + 1) return false;
221     res.n = 0;
222     for(i = head; i < tail; ++i)
223         res.p[res.n++] = deq[i] * deq[i + 1];
224     res.p[res.n++] = deq[head] * deq[tail];
225     res.n = unique(res.p, res.p + res.n) - res.p;
226     res.p[res.n] = res.p[0];
227     return true;
228 }
229 
230 /*******************************************************************************************/
231 
232 Point p[MAXN], ans;
233 double f[15], sum[MAXN];
234 double len, sqrt2 = sqrt(2);
235 int c, n, d;
236 
237 void dfs(const Point &a, const Point &b, double len, int dep) {
238     if(dep == 0) {
239         ans = (b - a) * len / dist(a, b) + a;
240     } else {
241         for(int i = 1; i < n; ++i) {
242             if(sgn(sum[i] * dist(a, b) / dist(p[0], p[n - 1]) * f[dep] - len) < 0) continue;
243             double angle1 = atan2(p[n - 1].y - p[0].y, p[n - 1].x - p[0].x);
244             double angle2 = atan2(b.y - a.y, b.x - a.x);
245             Point o = rotate(p[i - 1], angle2 - angle1, p[0]);
246             o = (o - p[0]) * dist(a, b) / dist(p[0], p[n - 1]) + a;
247             Point t = rotate(p[i], angle2 - angle1, p[0]);
248             t = (t - p[0]) * dist(a, b) / dist(p[0], p[n - 1]) + a;
249             dfs(o, t, len - sum[i - 1] * f[dep] * dist(a, b) / dist(p[0], p[n - 1]), dep - 1);
250             return ;
251         }
252     }
253 }
254 
255 void solve() {
256     sum[0] = 0;
257     for(int i = 1; i < n; ++i) sum[i] = sum[i - 1] + dist(p[i - 1], p[i]);
258     f[1] = 1;
259     double tmp = sum[n - 1] / dist(p[0], p[n - 1]);
260     for(int i = 2; i <= d; ++i) f[i] = f[i - 1] * tmp;
261     dfs(p[0], p[n - 1], len * sum[n - 1] * f[d], d);
262 }
263 
264 int main() {
265     scanf("%d", &c);
266     while(c--) {
267         scanf("%d", &n);
268         for(int i = 0; i < n; ++i) p[i].read();
269         scanf("%d%lf", &d, &len);
270         solve();
271         printf("(%.10f,%.10f)\n", ans.x, ans.y);
272     }
273 }
View Code

 

posted @ 2013-11-11 14:57  Oyking  阅读(470)  评论(0编辑  收藏  举报