hdu 4629 Burning (扫描线)

Problem - 4629

  以前写过PSLG模拟的版本,今天写了一下扫描线做这题。

  其实这题可以用set存线段来做,类似于判断直线交的做法。不过实现起来有点麻烦,于是我就直接暴力求交点了。

代码如下:

  1 #include <set>
  2 #include <queue>
  3 #include <cmath>
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <iomanip>
  7 #include <iostream>
  8 #include <algorithm>
  9 
 10 using namespace std;
 11 
 12 const double EPS = 1e-10;
 13 inline int sgn(double x) { return (x > EPS) - (x < -EPS);}
 14 typedef pair<double, double> Point;
 15 #define x first
 16 #define y second
 17 Point operator + (Point a, Point b) { return Point(a.x + b.x, a.y + b.y);}
 18 Point operator - (Point a, Point b) { return Point(a.x - b.x, a.y - b.y);}
 19 Point operator * (Point a, double p) { return Point(a.x * p, a.y * p);}
 20 Point operator / (Point a, double p) { return Point(a.x / p, a.y / p);}
 21 
 22 inline double cross(Point a, Point b) { return a.x * b.y - a.y * b.x;}
 23 inline double dot(Point a, Point b) { return a.x * b.x + a.y * b.y;}
 24 inline double veclen(Point a) { return sqrt(dot(a, a));}
 25 inline Point rotate(Point a) {
 26     double cosx = cos(0.001), sinx = sin(0.001);
 27     return Point(a.x * cosx - a.y * sinx, a.x * sinx + a.y * cosx);
 28 }
 29 
 30 struct Line {
 31     Point s, t;
 32     Line() {}
 33     Line(Point s, Point t) : s(s), t(t) {}
 34     Point vec() { return t - s;}
 35     Point point(double p) { return s + vec() * p;}
 36 } ;
 37 inline Point llint(Line a, Line b) { return a.point(cross(b.vec(), a.s - b.s) / cross(a.vec(), b.vec()));}
 38 void scan(Point &a) { cin >> a.x >> a.y;}
 39 const int N = 55;
 40 Point tri[N][4];
 41 
 42 bool check(int n) {
 43     for (int i = 0; i < n; i++) {
 44         for (int j = 0; j < 3; j++) {
 45             if (sgn(tri[i][j].x - tri[i][j + 1].x) == 0) return 1;
 46         }
 47     }
 48     return 0;
 49 }
 50 void adjust(int n) { for (int i = 0; i < n; i++) for (int j = 0; j < 4; j++) tri[i][j] = rotate(tri[i][j]);}
 51 inline bool between(Point p, Point a, Point b) { return sgn(dot(a - p, b - p)) <= 0;}
 52 bool cmpy(Point a, Point b) { return a.y < b.y;}
 53 
 54 bool triline(Line l, int id, Point *ip) {
 55     Point tmp[3];
 56     int tt = 0;
 57     for (int i = 0; i < 3; i++) {
 58         tmp[tt] = llint(l, Line(tri[id][i], tri[id][i + 1]));
 59         if (between(tmp[tt], tri[id][i], tri[id][i + 1])) tt++;
 60     }
 61     sort(tmp, tmp + tt, cmpy);
 62     ip[0] = tmp[0], ip[1] = tmp[tt - 1];
 63     return tt > 1;
 64 }
 65 
 66 typedef pair<double, int> Break;
 67 bool cmp(Break a, Break b) { return sgn(a.x - b.x) < 0 || sgn(a.x - b.x) == 0 && a.y < b.y;}
 68 Break ips_l[N << 2], ips_r[N << 2];
 69 double area[N], len_l[N], len_r[N], event[N * N << 4];
 70 void scanline(int n) {
 71     memset(area, 0, sizeof(area));
 72     int tt = 0;
 73     for (int i = 0; i < n; i++) {
 74         for (int j = 0; j < 3; j++) {
 75             Point a = tri[i][j], b = tri[i][j + 1];
 76             event[tt++] = a.x;
 77             for (int k = 0; k < n; k++) {
 78                 for (int l = 0; l < 3; l++) {
 79                     Point c = tri[k][l], d = tri[k][l + 1];
 80                     if (sgn(cross(b - a, d - c)) == 0) continue;
 81                     Point ip = llint(Line(a, b), Line(c, d));
 82                     //cout << ip.x << ' ' << ip.y << endl;
 83                     if (between(ip, a, b) && between(ip, c, d)) {
 84                         event[tt++] = ip.x;
 85                     }
 86                 }
 87             }
 88         }
 89     }
 90     sort(event, event + tt);
 91     tt = (int) (unique(event, event + tt) - event);
 92     Line cur;
 93     Point tmp[2];
 94     for (int i = 1, c, cnt; i < tt; i++) {
 95         if (sgn(event[i - 1] - event[i]) == 0) continue;
 96         c = 0;
 97         cur = Line(Point(event[i - 1] + EPS, 0.0), Point(event[i - 1] + EPS, 1.0));
 98         for (int j = 0; j < n; j++) {
 99             if (triline(cur, j, tmp)) {
100                 ips_l[c++] = Break(tmp[0].y, 1), ips_l[c++] = Break(tmp[1].y, -1);
101             }
102         }
103         sort(ips_l, ips_l + c, cmp);
104         cnt = 0;
105         memset(len_l, 0, sizeof(len_l));
106         for (int j = 0; j < c; j++) {
107             if (cnt > 0) len_l[cnt] += ips_l[j].x - ips_l[j - 1].x;
108             cnt += ips_l[j].y;
109         }
110         c = 0;
111         cur = Line(Point(event[i] - EPS, 0.0), Point(event[i] - EPS, 1.0));
112         for (int j = 0; j < n; j++) {
113             if (triline(cur, j, tmp)) {
114                 ips_r[c++] = Break(tmp[0].y, 1), ips_r[c++] = Break(tmp[1].y, -1);
115             }
116         }
117         sort(ips_r, ips_r + c, cmp);
118         cnt = 0;
119         memset(len_r, 0, sizeof(len_r));
120         for (int j = 0; j < c; j++) {
121             if (cnt > 0) len_r[cnt] += ips_r[j].x - ips_r[j - 1].x;
122             cnt += ips_r[j].y;
123         }
124         for (int j = 1; j <= n; j++) area[j] += (len_l[j] + len_r[j]) * (event[i] - event[i - 1]) / 2;
125     }
126 }
127 
128 int main() {
129     ios::sync_with_stdio(0);
130     cout << setiosflags(ios::fixed) << setprecision(8);
131     int T, n;
132     cin >> T;
133     while (T-- && cin >> n) {
134         int tt = 0;
135         for (int i = 0; i < n; i++) {
136             for (int j = 0; j < 3; j++) scan(tri[tt][j]);
137             tri[tt][3] = tri[tt][0];
138             if (sgn(cross(tri[tt][1] - tri[tt][0], tri[tt][2] - tri[tt][0]))) tt++;
139         }
140         while (check(tt)) adjust(tt);
141         scanline(tt);
142         for (int i = 1; i <= n; i++) area[i] = fabs(area[i]);
143         for (int i = 1; i <= n; i++) cout << area[i] << endl;
144     }
145     return 0;
146 }
View Code

——written by Lyon

原文地址:https://www.cnblogs.com/LyonLys/p/hdu_4629_Lyon.html