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.
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.
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 }