POJ 1514 - Metal Cutting
http://poj.org/problem?id=1514
概要
(0,0), (0,m), (n,m), (n,0) という座標を頂点とした n * m の鉄板がある. これを cutting machine で切って,与えられた座標を頂点とする凸な p 角形を切り出したい.
cutting machine は多角形の端から端までしか切ることができない. つまり,鉄板の途中まで切って向きを変えるというような操作はできない.
切った長さを最小にしたい.そのときの長さを答える.
制約
- 3 <= p <= 8
- 0 < n, m <= 500
解法
全探索 + 多角形の切断で O(p! * p * p).
切断するときに交点を覚えておいて,切った長さも返すように実装した.
poj/1514.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 cross(const P& a, const P& b) 9 { 10 return a.real()*b.imag() - b.real()*a.imag(); 11 } 12 13 struct line 14 { 15 P a, b; 16 line() {} 17 line(const P& x, const P& y) : a(x), b(y) {} 18 19 inline bool parallel(const line& ln) const 20 { 21 return abs(cross(ln.b - ln.a, b - a)) < EPS; 22 } 23 24 inline bool intersects(const line& ln) const 25 { 26 return !parallel(ln); 27 } 28 29 inline P intersection(const line& ln) const 30 { 31 const P x = b - a; 32 const P y = ln.b - ln.a; 33 return a + x*(cross(y, ln.a - a))/cross(y, x); 34 } 35 }; 36 37 struct segment 38 { 39 P a, b; 40 segment() {} 41 segment(const P& x, const P& y) : a(x), b(y) {} 42 43 inline bool intersects(const line& ln) const 44 { 45 return cross(ln.b - ln.a, a - ln.a) * cross(ln.b - ln.a, b - ln.a) < EPS; 46 } 47 48 inline P intersection(const line& ln) const 49 { 50 const P x = b - a; 51 const P y = ln.b - ln.a; 52 return a + x*(cross(y, ln.a - a))/cross(y, x); 53 } 54 55 inline bool parallel(const line& ln) const 56 { 57 return abs(cross(ln.b - ln.a, b - a)) < EPS; 58 } 59 }; 60 61 struct polygon 62 { 63 P ps[16]; 64 int N; 65 polygon() : N(0) {} 66 67 inline int size() const { return N; } 68 inline void push_back(const P& p) { ps[N++] = p; } 69 inline P& operator[](int i) { return ps[i]; } 70 inline const P& operator[](int i) const { return ps[i]; } 71 72 pair<polygon,double> cut(const line& ln) const 73 { 74 // cut out the left-side of the line 75 polygon ret; 76 P crosspoint[2]; 77 int cp = 0; 78 for (int i = 0; i < N; i++) { 79 const segment seg(ps[i], ps[(i+1)%N]); 80 if (cross(ln.b - ln.a, ps[i] - ln.a) < EPS) { 81 // ps[i] is right-side of the line 82 ret.push_back(ps[i]); 83 if (!seg.parallel(ln) && seg.intersects(ln)) { 84 const P p = seg.intersection(ln); 85 if (abs(p - ps[i]) > EPS) { 86 ret.push_back(p); 87 crosspoint[cp++] = p; 88 } 89 } 90 } else if (!seg.parallel(ln) && seg.intersects(ln)) { 91 const P p = seg.intersection(ln); 92 ret.push_back(p); 93 crosspoint[cp++] = p; 94 } 95 } 96 if (cp == 2) { 97 return make_pair(ret, abs(crosspoint[1] - crosspoint[0])); 98 } else { 99 throw "???"; 100 } 101 } 102 }; 103 104 int main() 105 { 106 int n, m; 107 scanf("%d %d", &n, &m); 108 int p; 109 scanf("%d", &p); 110 P ps[8]; 111 for (int i = 0; i < p; i++) { 112 int x, y; 113 scanf("%d %d", &x, &y); 114 ps[i] = P(x, y); 115 } 116 line ls[8]; 117 int a[8]; 118 for (int i = 0; i < p; i++) { 119 ls[i] = line(ps[i], ps[(i+1)%p]); 120 a[i] = i; 121 } 122 123 double ans = 1e9; 124 do { 125 polygon poly; 126 poly.push_back(P(0, 0)); 127 poly.push_back(P(0, m)); 128 poly.push_back(P(n, m)); 129 poly.push_back(P(n, 0)); 130 double len = 0.0; 131 for (int i = 0; i < p; i++) { 132 const pair<polygon,double> r = poly.cut(ls[a[i]]); 133 len += r.second; 134 poly = r.first; 135 } 136 ans = min(ans, len); 137 } while (next_permutation(a, a+p)); 138 printf("Minimum total length = %.3f\n", ans); 139 return 0; 140 }