POJ 1271 - Nice Milk
http://poj.org/problem?id=1271
概要
凸な n 角形のパンを高さ h のミルクに k 回までつけたとき,最大でどれくらいの面積をミルクにつけることができるかを答える.
制約
- 3 <= n <= 20
- 0 <= k <= 8
- 0 <= h <= 10
- 0 <= パンの頂点の座標 <= 1000
- パンの頂点の座標は反時計回りに与えられる
解法
全探索 + 多角形の切断.
ミルクをつける辺が同じならば順番は関係ないので,C(n,k)
で全探索できる.
多角形の切断は n でできるため,全体で n * C(n,k)
でだいたい 2.5 * 10^6 程度.
テストケースが最大10個で,浮動小数演算も多いので結構時間が厳しい. 実際 TLE を連発した. 最終的に vector を配列に変えることで通った… (297MS)
それと k <= n とは限らないことに注意. 最初これで RE を出した.
poj/1271.cc1 #include <cstdio> 2 #include <algorithm> 3 #include <complex> 4 using namespace std; 5 typedef complex<double> P; 6 static const double EPS = 1e-6; 7 8 inline double dot(const P& a, const P& b) 9 { 10 return a.real()*b.real() + a.imag()*b.imag(); 11 } 12 13 inline double cross(const P& a, const P& b) 14 { 15 return a.real()*b.imag() - b.real()*a.imag(); 16 } 17 18 struct line 19 { 20 P base, dir; 21 line() {} 22 line(const P& x, const P& y) : base(x), dir(y - x) {} 23 }; 24 25 struct segment 26 { 27 P a, b; 28 segment() {} 29 segment(const P& x, const P& y) : a(x), b(y) {} 30 31 inline bool intersects(const line& ln) const 32 { 33 return cross(ln.dir, a - ln.base) * cross(ln.dir, b - ln.base) < EPS; 34 } 35 36 inline P intersection(const line& ln) const 37 { 38 const P x = b - a; 39 return a + x*(cross(ln.dir, ln.base - a))/cross(ln.dir, x); 40 } 41 42 inline bool parallel(const line& ln) const 43 { 44 return abs(cross(ln.dir, b - a)) < EPS; 45 } 46 }; 47 48 struct polygon 49 { 50 int N; 51 P ps[25]; 52 polygon() : N(0) {} 53 54 inline int size() const { return N; } 55 inline void push_back(const P& p) { ps[N++] = p; } 56 inline P& operator[](int i) { return ps[i]; } 57 inline const P& operator[](int i) const { return ps[i]; } 58 59 double area() const 60 { 61 // positive if polygon is clockwise 62 double a = 0.0; 63 for (int i = 0; i < N; i++) { 64 a += cross(ps[(i+1)%N], ps[i]); 65 } 66 return a/2.0; 67 } 68 69 polygon cut(const line& ln) const 70 { 71 // cut out the left-side of the line 72 polygon ret; 73 segment seg; 74 for (int i = 0; i < N; i++) { 75 seg.a = ps[i]; 76 seg.b = ps[(i+1)%N]; 77 if (cross(ln.dir, ps[i] - ln.base) < EPS) { 78 // ps[i] is right-side of the line 79 ret.push_back(ps[i]); 80 if (!seg.parallel(ln) && seg.intersects(ln)) { 81 const P p = seg.intersection(ln); 82 if (abs(p - ps[i]) > EPS) { 83 ret.push_back(p); 84 } 85 } 86 } else if (!seg.parallel(ln) && seg.intersects(ln)) { 87 ret.push_back(seg.intersection(ln)); 88 } 89 } 90 return ret; 91 } 92 }; 93 94 double dfs(const line *ls, int N, const polygon& poly, int i, int depth) 95 { 96 if (depth == 0) { 97 return poly.area(); 98 } else { 99 double ans = poly.area(); 100 for (int j = i+1; j < N; j++) { 101 ans = min(ans, dfs(ls, N, poly.cut(ls[j]), j, depth-1)); 102 } 103 return ans; 104 } 105 } 106 107 int main() 108 { 109 int N, K, H; 110 while (scanf("%d %d %d", &N, &K, &H) != EOF && N != 0) { 111 K = min(K, N); 112 polygon poly; 113 for (int i = 0; i < N; i++) { 114 int x, y; 115 scanf("%d %d", &x, &y); 116 poly.push_back(P(x, y)); 117 } 118 if (K == 0 || H == 0) { 119 puts("0.00"); 120 continue; 121 } 122 reverse(poly.ps, poly.ps + N); 123 124 static line ls[20]; 125 for (int i = 0; i < N; i++) { 126 const P& p1 = poly[i]; 127 const P& p2 = poly[(i+1)%N]; 128 const P dir = p2 - p1; 129 const P n = dir*P(0.0, -1.0); 130 const P h = H/abs(n)*n + p1; 131 ls[i] = line(h, h + dir); 132 } 133 printf("%.2f\n", poly.area() - dfs(ls, N, poly, -1, K)); 134 } 135 return 0; 136 }