SRM 239 DIV1 Hard HiddenTriangles
問題
座標軸に平行か45°斜めかのどちらかの線分が複数与えられる。
この中作ることができる三角形を数えろ
- 0 <= 線分の数 <= 50
- 線分はオーバーラップすることもある
解答
まず、重複しないように辺をマージする。
次に、線分同士で交差する点を全部列挙する。
斜めは45°なので、最初に座標を2倍すれば交差する点は整数座標で表せる。
任意の辺で繋がった2点を考えると、辺の向きによってちょうど2つの可能な三角形がわかる。
それをチェックして数える
コメント
ぐちゃぐちゃになってしまった。
何時間もかかってるし一回セグフォで落ちてるし…
もっと普通にできたい
コード
#include <vector> #include <algorithm> #include <cmath> #include <cstring> #define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i)) #define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i)) #define each(it,o) for(__typeof((o).begin()) it = (o).begin(); it != (o).end(); ++ it) #define all(o) (o).begin(), (o).end() #define pb(x) push_back(x) #define mset(m,v) memset(m,v,sizeof(m)) using namespace std; typedef vector<int> vi; typedef long long ll; struct P { typedef int T; typedef ll T2; //T2は{a*b | a:T, b:T}を含むタイプ T x, y; P(T x_, T y_): x(x_), y(y_) {} P(): x(0), y(0) {} }; struct L { P a, b; L(const P &a_, const P &b_): a(a_), b(b_) {} const P& operator[](size_t i) const { return i ? b : a; } }; inline bool operator==(const P& a, const P& b) { return a.x == b.x && a.y == b.y; } inline bool operator<(const P& a, const P& b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } inline P operator+(const P& a, const P& b) { return P(a.x+b.x, a.y+b.y); } inline P operator-(const P& a, const P& b) { return P(a.x-b.x, a.y-b.y); } inline P::T2 cross(const P& a, const P& b) { return (P::T2)a.x*b.y - (P::T2)a.y*b.x; } inline P::T2 norm(const P& a) { return (P::T2)a.x*a.x + (P::T2)a.y*a.y; } inline P operator*(P::T a, const P& b) { return P(a * b.x, a * b.y); } inline P operator/(const P& a, P::T b) { return P(a.x / b, a.y / b); } inline int ccw(const P& a, const P& b, const P& c) { int ax = b.x - a.x, ay = b.y - a.y, bx = c.x - a.x, by = c.y - a.y; P::T2 t = (P::T2)ax*by - (P::T2)ay*bx; if (t > 0) return 1; if (t < 0) return -1; if((P::T2)ax*bx + (P::T2)ay*by < 0) return +2; if((P::T2)ax*ax + (P::T2)ay*ay < (P::T2)bx*bx + (P::T2)by*by) return -2; return 0; } P crosspoint(const L &l, const L &m) { P::T2 A = cross(l[1] - l[0], m[1] - m[0]); P::T2 B = cross(l[1] - l[0], l[1] - m[0]); if(A == 0 && B == 0) return m[0]; return m[0] + B * (m[1] - m[0]) / A; } int intersectSS(const L &s, const L &t) { int a = ccw(s.a,s.b,t.a), b = ccw(s.a,s.b,t.b), c = ccw(t.a,t.b,s.a), d = ccw(t.a,t.b,s.b); int x = a * b, y = c * d; if(x == -1 && y == -1) return 0; //cross else if( ((abs(b) == 1 || b == -2) && s.b == t.a) || ((abs(b) == 1 || b == 2) && s.a == t.a) || ((abs(a) == 1 || a == -2) && s.b == t.b) || ((abs(a) == 1 || a == 2) && s.a == t.b) ) return 4; // point overlap else if( (x == 0 && (abs(a) + abs(b) == 1)) || (y == 0 && (abs(c) + abs(d) == 1)) ) return 2; // point overlap else if(x <= 0 && y <= 0) return 3; //segment overlap else return 1; } struct HiddenTriangles { int dir(L l) { P p = l.b - l.a; return p.x == 0 ? 0 : p.y == 0 ? 1 : (P::T2)p.x * p.y > 0 ? 2 : 3; } static inline int coordinateIndex(int x, int y) { return (x + 450) * 900 + (y + 450); } int howMany(vector <int> X1, vector <int> Y1, vector <int> X2, vector <int> Y2) { int n = X1.size(); vector<L> ls; rep(i, n) ls.pb(L(2 * P(X1[i], Y1[i]), 2 * P(X2[i], Y2[i]))); static bool dupl[50]; mset(dupl, 0); rep(i, n) reu(j, i+1, n) if(!dupl[j] && intersectSS(ls[i], ls[j]) >= 3 && dir(ls[i]) == dir(ls[j])) { L l = L(min(min(ls[i].a, ls[i].b), min(ls[j].a, ls[j].b)), max(max(ls[i].a, ls[i].b), max(ls[j].a, ls[j].b))); ls[i] = l; dupl[j] = true; --i; break; } { vector<L> nls; rep(i, n) if(!dupl[i]) nls.pb(ls[i]); ls.swap(nls); n = ls.size(); } vector<P> ps; rep(i, n) { ps.pb(ls[i].a), ps.pb(ls[i].b); } rep(i, n) reu(j, i+1, n) { int c = intersectSS(ls[i], ls[j]); if(c == 0 || c == 2) { P p = crosspoint(ls[i], ls[j]); ps.pb(p); } } sort(all(ps)); ps.erase(unique(all(ps)), ps.end()); int m = ps.size(); static int index[1000*1000]; mset(index, -1); rep(i, m) index[coordinateIndex(ps[i].x, ps[i].y)] = i; int count = 0; vector<vi> ts(n); static bool edge[1500][1500]; mset(edge, 0); rep(i, n) { rep(j, m) if(ccw(ls[i].a, ls[i].b, ps[j]) == 0) ts[i].pb(j); each(j, ts[i]) each(k, ts[i]) edge[*j][*k] = true; } rep(i, n) { const vi& t = ts[i]; int d = dir(ls[i]); rep(p1, t.size()) { int px = ps[t[p1]].x, py = ps[t[p1]].y; reu(p2, p1+1, t.size()) { int qx = ps[t[p2]].x, qy = ps[t[p2]].y; #define CHECK(x, y) {\ int k = index[coordinateIndex(x, y)];\ if(k != -1 && edge[t[p1]][k] && edge[t[p2]][k])\ count ++;\ } switch(d) { case 0: if((qy - py) % 2 == 0) { CHECK(px + (qy - py) / 2, (qy + py) / 2); CHECK(px - (qy - py) / 2, (qy + py) / 2); } break; case 1: if((qx - px) % 2 == 0) { CHECK((qx + px) / 2, py + (qx - px) / 2); CHECK((qx + px) / 2, py - (qx - px) / 2); } break; case 2: case 3: CHECK(px, qy); CHECK(qx, py); break; } } } } return count; } };