Time Limit: 10000MS Memory Limit: 10000K
Total Submissions: 403 Accepted: 172
Description
In order to build a ship to travel to Eindhoven, The Netherlands, various sheet metal parts have to be cut from rectangular pieces of sheet metal. Each part is a convex polygon with at most 8 vertices. Each rectangular piece of sheet metal has width n and height m, so that the four corners of the sheet can be specified by the Cartesian coordinates (0, 0), (0, m), (n, m) and (n, 0) in clockwise order. The cutting machine available can make only straight-line cuts completely through the metal. That is, it cannot cut halfway through the sheet, turn, and then cut some more. You are asked to write a program to determine the minimum total length of cuts this machine has to make in order to cut out the polygon. The cuts must be along the edges of the poligon.
For example, if n = m = 100, and the polygon has vertices (80, 80), (70, 30), (20, 20) and (20, 80), the following diagram shows the optimal cut (the thick lines). The numbers show the order in which the cuts are made.
Input
The first line of input contains the two integers n and m where 0 < n, m <= 500. The next line contains p, the number of vertices in the polygon, where 3 <= p <= 8. Each of the next p lines contains two integers x and y where 0 < x < n and 0 < y < m, specifying the vertices of the polygon. The vertices are listed in clockwise order. You may assume that the polygon does not intersect itself, and that no three consecutive vertices are colinear.
Output
Print the minimum total length of cuts required to cut out the given polygon, accurate to 3 decimal places.
Sample Input
100 100
4
80 80
70 30
20 20
20 80
Sample Output
Minimum total length = 312.575
Source
East Central North America 1998
题目大意:
一张正方形纸上有p个凸包的顶点。每次选择凸包的一条边沿着这条边将纸成两块,直到把纸剪成凸包。问按照怎样的顺序剪才能使剪的长度最短。
思路:
这题第一眼的做法应该是暴力枚举剪的顺序, 然后用半平面交模拟剪纸的过程。
其实还有更简单的做法,对每一次剪纸的长度只与当前边的左右的边是否剪过有关,只要处理出当前边的左右是否被剪过,就可以通过枚举或者状压DP求出答案,详情百度狗狗40题参照watashi博客。
不过作为弱逼还是只想到了做半平面交,于是写了一个N^2的半平面交。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <ctime>
#include <bitset>
#include <algorithm>
#include <set>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <stack>
#include <queue>
#include <deque>
#define LL long long
#define PC polygon_convex
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
int cmp(double x) {
if(fabs(x) < eps) return 0;
if(x > 0)return 1;
return -1;
}
inline double sqr(double x) {
return x * x;
}
struct point {
double x, y;
point(){}
point(double a, double b): x(a), y(b) {}
void input(){
scanf("%lf%lf",&x,&y);
}
friend point operator + (const point &a, const point &b) {
return point(a.x + b.x, a.y + b.y);
}
friend point operator - (const point &a, const point &b) {
return point(a.x - b.x, a.y - b.y);
}
friend bool operator == (const point &a, const point &b) {
return cmp(a.x - b.x) == 0 && cmp(a.y - b.y) == 0;
}
friend point operator * (const point &a, const double &b) {
return point(a.x * b, a.y * b);
}
friend point operator * (const double &a, const point &b) {
return point(a * b.x, a * b.y);
}
friend point operator / (const point &a, const double &b) {
return point(a.x / b, a.y / b);
}
double norm(){
return sqrt(sqr(x) + sqr(y));
}
};
double det(const point &a, const point &b) {
return a.x * b.y - a.y * b.x;
}
double dot(const point &a, const point &b) {
return a.x * b.x + a.y * b.y;
}
double dist(const point &a, const point &b) {
return (a - b).norm();
}
double Angle(point a, point b) {
if(cmp(dot(a, b) - a.norm() * b.norm()) == 0) return 0;
return acos(dot(a,b) / a.norm() / b.norm());
}
point rotate_point(const point &p, double A){
double tx = p.x, ty = p.y;
return point(tx * cos(A) - ty * sin(A), tx * sin(A) + ty * cos(A));
}
struct line {
point a, b;
line(){}
line(point x, point y):a(x),b(y){}
};
line point_make_line(const point a, const point b) {
return line(a,b);
}
double dis_point_segment(const point p, const point s, const point t) {
if(cmp(dot(p - s, t - s))<0) return (p-s).norm();
if(cmp(dot(p - t, s - t))<0) return (p-t).norm();
return fabs(det(s - p, t - p) / dist(s, t));
}
void PointProjLine(const point p, const point s, const point t, point &cp) {
double r = dot(t - s, p - s) / dot (t - s, t - s);
cp = s + r * (t - s);
}
bool PointOnSegment(point p, point s, point t) {
return cmp(det(p - s, t - s))==0 && cmp(dot(p - s, p - t)) <= 0;
}
bool parallel(line a, line b) {
return !cmp(det(a.a - a.b, b.a - b.b));
}
bool line_make_point(line a, line b, point &res){
if(parallel(a, b)) return false;
double s1 = det(a.a - b.a, b.b - b.a);
double s2 = det(a.b - b.a, b.b - b.a);
res = (s1 * a.b - s2 * a.a) / (s1 - s2);
return true;
}
const int maxn = 100;
struct polygon {
int n;
point a[maxn];
polygon() {}
double perimeter() {
double sum = 0;
a[n] = a[0];
for (int i = 0; i < n; i++) sum += (a[i+1] - a[i]).norm();
return sum;
}
double area() {
double sum = 0;
a[n] = a[0];
for (int i = 0; i < n; i++) sum += det(a[i+1], a[i]);
return sum/2.;
}
int Point_In(point t){
int num = 0, i, d1, d2, k;
a[n] = a[0];
for(i = 0; i < n; i++){
if(PointOnSegment(t, a[i], a[i+1])) return 2;
k = cmp(det(a[i+1] - a[i], t - a[i]));
d1 = cmp(a[i].y - t.y);
d2 = cmp(a[i+1].y - t.y);
if( k > 0 && d1 <= 0 && d2 > 0) num++;
if( k < 0 && d2 <= 0 && d1 > 0) num--;
}
return num != 0;
}
point MassCenter() {
point ans = point(0, 0);
if(cmp(area()) == 0) return ans;
a[n] = a[0];
for (int i = 0; i < n; i++) ans = ans + (a[i] + a[i + 1]) * det(a[i + 1], a[i]);
return ans / area() / 6.;
}
};
struct polygon_convex {
vector<point> P;
polygon_convex(int Size = 0) {
P.resize(Size);
}
double perimeter() {
double ret = 0;
int n = P.size();
#define next(i) ( (i + 1) % n)
for(int i = 0; i < n; i++) ret += (P[i] - P[next(i)]).norm();
return ret;
}
double area() {
double ret = 0;
int n = P.size();
#define next(i) ( (i + 1) % n)
for(int i = 0 ;i < n; i++)ret += det(P[next(i)], P[i]);
return ret / 2;
}
};
bool comp_less(const point &a, const point &b){
return cmp(a.x -b.x) < 0 || cmp(a.x - b.x) == 0 && cmp (a.y - b.y) < 0;
}
polygon_convex convex_hull(vector<point> a) {
polygon_convex res(2 * a.size() + 5);
sort(a.begin(), a.end(), comp_less);
a.erase(unique(a.begin(), a.end()), a.end());
int m = 0;
for(int i = 0; i < a.size(); i++){
while( m > 1 && cmp(det(res.P[m-1] - res.P[m-2], a[i] - res.P[m - 2])) <= 0) m--;
res.P[m++] = a[i];
}
int k = m;
for(int i = int(a.size()) - 2; i >= 0; i--) {
while(m > k && cmp(det(res.P[m-1] - res.P[m-2], a[i] - res.P[m-2])) <= 0) m--;
res.P[m++] = a[i];
}
res.P.resize(m);
if(a.size() > 1) res.P.resize(m-1);
return res;
}
vector<point> p;
int a[10], N, M, n;
PC pc;
double ans;
bool flag[10];
PC new_pol, pol;
point A, B, C, D;
vector<point> cut;
double calc() {
double ret = 0;
p.clear();
p.push_back(point(0, 0));
p.push_back(point(N, 0));
p.push_back(point(N, M));
p.push_back(point(0, M));
pol = convex_hull(p);
int m = pc.P.size();
for(int i = 0; i < m; i++) {
A = pc.P[a[i]];
B = pc.P[(a[i] + 1) % m];
new_pol.P.clear();
cut.clear();
for(int j = 0; j < (int)pol.P.size(); j++) {
C = pol.P[j];
D = pol.P[(j + 1) % pol.P.size()];
if(cmp(det(B - A, C - A)) >= 0) new_pol.P.push_back(C);
if(cmp(det(B - A, C - D)) != 0) {
point ip;
if(line_make_point(line(A, B), line(C, D), ip) && PointOnSegment(ip, C, D)) {
new_pol.P.push_back(ip);
cut.push_back(ip);
}
}
}
sort(cut.begin(), cut.end(), comp_less);
cut.erase(unique(cut.begin(), cut.end()), cut.end());
ret += (cut[0] - cut[1]).norm();
pol = new_pol;
}
return ret;
}
void search(int x) {
if(x >= pc.P.size()) {
double t = calc();
ans = min(ans, t);
return;
}
for (int i = 0; i < (int)pc.P.size(); i++) if(!flag[i]) {
a[x] = i;
flag[i] = true;
search(x + 1);
flag[i] = false;
}
}
int main() {
int T;
scanf("%d", &T);
while(T--) {
//init();
scanf("%d%d", &N, &M);
scanf("%d", &n);
p.resize(n);
for(int i = 0; i < n; i++) p[i].input();
pc = convex_hull(p);
ans = 1234567890;
search(0);
printf("Minimum total length = %.3f\n", ans);
if(T) puts("");
}
return 0;
}