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

 

题目大意:给你一个长为m宽为n的木板再给你一个凸的p边形的p个坐标点,求最短切割路径长度(这里割只能一刀子到头,不能停不能弯)。

Wrong啦:这题由于最多为8边形,所以果断采用暴力方法,枚举所有切割次序,注意这里的切割最好用半平面法来做,不然要考虑的情况特别多,其中我刚开始拿到这题就当成普通的几何问题来做,把每个割痕分为3部分l1、l2、l3再利用深搜动态的调整每一个割痕对应的l1/l2/l3的值,同时考虑边界切割问题和l1或l3为0的情况,结果都不能过,最后发现少考虑了一种最坑的情况,即:非常大木板与非常小正六边形问题(这里会产生新割痕对旧割痕的影响,所以不得不换用另一种思路!

 #include<iostream>
#include<math.h>
#include<cstdio>
#include<algorithm>
using namespace std;
class point{
public:
double x,y;
bool in(int n,int m){
return (x>= && n>=x && y>= && m>=y);
}
};
void chose(point a1,point a2,point a3,point a4,point &a5,point &a6,int n,int m){
bool ok=;
if(a1.in(n,m))a5.x=a1.x,a5.y=a1.y,ok=;
if(a2.in(n,m)){
if(ok){a6.x=a2.x;a6.y=a2.y;return;}
else a5.x=a2.x,a5.y=a2.y,ok=;
}
if(a3.in(n,m)){
if(ok){a6.x=a3.x;a6.y=a3.y;return;}
else a5.x=a3.x,a5.y=a3.y,ok=;
}
if(a4.in(n,m))a6.x=a4.x,a6.y=a4.y;
}
double dis(point a,point b){
return sqrt(1.0*(b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
}
class line{
public:
double l1,l2,l3;
int num;
bool set(point a,point b,int n,int m){
if(fabs(a.y-b.y)<0.00001){//横着的
if(fabs(a.y-m)<0.00000001 || fabs(a.y)<0.00000001){l1=l3=l2=;return ;}
else if(b.x>a.x){l1=a.x;l2=b.x-a.x;l3=n-b.x;}
else {l1=n-a.x;l2=a.x-b.x;l3=b.x;}
}else if(fabs(a.x-b.x)<0.00001){//竖着的
if(fabs(a.x-n)<0.00000001 || fabs(a.x)<0.00000001){l1=l3=l2=;return ;}
else if(a.y>b.y){l1=m-a.y;l2=a.y-b.y;l3=b.y;}
else {l1=a.y;l2=b.y-a.y;l3=m-b.y;}
}else{//其他情况
l2=sqrt(1.0*(b.x-a.x)*(b.x-a.x)+(b.y-a.y)*(b.y-a.y));
double k=(b.y-a.y)/(b.x-a.x);
point PJ[];
PJ[].x=;PJ[].y=a.y-a.x*k;
PJ[].x=a.x-a.y/k;PJ[].y=;
PJ[].x=n;PJ[].y=a.y+(n-a.x)*k;
PJ[].x=a.x+(m-a.y)/k;PJ[].y=m;
/*for(int i=0;i<4;i++)
cout<<PJ[i].x<<' '<<PJ[i].y<<'\n';*/
chose(PJ[],PJ[],PJ[],PJ[],PJ[],PJ[],n,m);
//cout<<PJ[4].x<<' '<<PJ[4].y<<' '<<PJ[5].x<<' '<<PJ[5].y<<'\n';
if(PJ[].x>PJ[].x){
PJ[]=PJ[];
PJ[]=PJ[];
PJ[]=PJ[];
}
if(a.x<b.x){//a在左
l1=dis(PJ[],a);
l3=dis(PJ[],b);
}else{
l1=dis(a,PJ[]);
l3=dis(b,PJ[]);
}
}return ;
} };
bool operator<(line L1,line L2){
return (L1.l1+L1.l3)<(L2.l1+L2.l3);
} //---------------------------------------
line L[];
int p,lose;
int vis[];
double minRoad,proRoad;
void dfs(int c){
bool ok=;
for(int i=;i<p-lose;i++)if(!vis[i]){
int cur=L[i].num;
int pre=(cur+)%p;double prel3;
int next=(cur+)%p;double nextl1; proRoad+=(L[i].l1+L[i].l2+L[i].l3);vis[i]=;
for(int j=;j<p;j++){//减掉L[c]对其前后的影响
if(L[j].num==pre){prel3=L[j].l3;L[j].l3=;}
else if(L[j].num==next){nextl1=L[j].l1;L[j].l1=;}
}
dfs(i);
proRoad-=(L[i].l1+L[i].l2+L[i].l3);vis[i]=;
for(int j=;j<p;j++){//恢复L[c]对其前后的影响
if(L[j].num==pre)L[j].l3=prel3;
else if(L[j].num==next)L[j].l1=nextl1;
}
ok=;
}
if(!ok){//没有要剪得,表明已经剪完
if(proRoad<minRoad)minRoad=proRoad;
}
}
void Solve(){
minRoad=;proRoad=;
for(int i=;i<;i++)vis[i]=;
for(int i=;i<p-lose;i++){
int cur=L[i].num;
int pre=(cur+)%p;double prel3;
int next=(cur+)%p;double nextl1; proRoad+=(L[i].l1+L[i].l2+L[i].l3);vis[i]=;
for(int j=;j<p;j++){//减掉L[c]对其前后的影响
if(L[j].num==pre){prel3=L[j].l3;L[j].l3=;}
else if(L[j].num==next){nextl1=L[j].l1;L[j].l1=;}
}
dfs(i);
proRoad-=(L[i].l1+L[i].l2+L[i].l3);vis[i]=;
for(int j=;j<p;j++){//恢复L[c]对其前后的影响
if(L[j].num==pre)L[j].l3=prel3;
else if(L[j].num==next)L[j].l1=nextl1;
}
}
}
//-------------------------------------
int main(){
int T;cin>>T;int ok=;
while(T--){
int n,m;cin>>n>>m;
cin>>p;
point P[];
for(int i=;i<p;i++)cin>>P[i].x>>P[i].y;
lose=;
for(int i=;i<p;i++){
lose+=!L[i].set(P[i],P[(i+)%p],n,m);
L[i].num=i;
}
/*for(int i=0;i<p;i++){
cout<<L[i].l1<<' '<<L[i].l2<<' '<<L[i].l3<<'\n';
}*/
sort(L,L+p);
/*for(int i=0;i<p;i++){
cout<<L[i].l1<<' '<<L[i].l2<<' '<<L[i].l3<<'\n';
}*/ /*double sum=0;
for(int i=0;i<p-lose;i++){
sum+=(L[0].l1+L[0].l2+L[0].l3);
L[0].l1=10000000;
int cur=L[0].num;
int pre=(cur+7)%p;
int next=(cur+1)%p;
for(int j=0;j<p;j++){
if(L[j].num==pre)L[j].l3=0;
else if(L[j].num==next)L[j].l1=0;
}
sort(L,L+p);
//for(int i=0;i<p;i++){
// cout<<L[i].l1<<' '<<L[i].l2<<' '<<L[i].l3<<'\n';
//}
}*/////贪心求法
Solve();//深搜求法
if(minRoad==)minRoad=;
if(ok)printf("\n");ok=;
printf("Minimum total length = %.3lf\n",minRoad);
}
}

错误代码

半平面法:最后想到了半平面的方法,就是把木板看成一个4个顶点的凸包,切出里面的p多边形即依次枚举切割顺序,对于每一次切割肯定沿着某一条边,这样最多8!种情况。然后每一次切割我用点集st[]维护每次切过后剩下的部分(新的凸包),np维护新凸包的顶点数。这里的维护就采用了半平面割的方法:

 #include <cmath>
#include <cstdio>
#include<algorithm>
using namespace std;
const int maxn = ; double min(double a,double b){return a<b?a:b;}//求2个double中较小的一个 const double eps = 1e-;
double sgn(double x) {return fabs(x)<eps?:(x>?:-);}//经典比较2个double类数的方法,相等0,大于1,小于-1
//------------------------------------------------------------------
//2维几何模板
//------------------------------------------------------------------
struct Point{//点类(x,y)构造函数+==重定义
double x,y;
Point(double tx=,double ty=){x=tx;y=ty;}
bool operator == (const Point& t) const {
return sgn(x-t.x)== && sgn(y-t.y)==;
}
}p[maxn],Set[maxn],st[maxn],tmp[maxn],pp[maxn]; double dist(Point a,Point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}//a、b两点的距离
double cross(Point a,Point b,Point c){return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);}//向量ab和向量ac的差积 struct Seg{Point s,e;};//射线se
bool outside(Seg seg,Point p){return cross(seg.s,seg.e,p)>eps;}//点p在射线seg左
bool inside(Seg seg,Point p){return cross(seg.s,seg.e,p)<-eps;}//点p在射线seg右 Point Intersect(Point p1, Point p2, Point p3, Point p4, Point& p) {
double a1, b1, c1, a2, b2, c2, d;
a1 = p1.y - p2.y; b1 = p2.x - p1.x; c1 = p1.x*p2.y - p2.x*p1.y;
a2 = p3.y - p4.y; b2 = p4.x - p3.x; c2 = p3.x*p4.y - p4.x*p3.y;
d = a1*b2 - a2*b1;
if ( fabs(d) < eps ) return false;
p.x = (-c1*b2 + c2*b1) / d;
p.y = (-a1*c2 + a2*c1) / d;
return p;
}//直线p1p2和p3p4的交点存在p中(当且仅当Cross(p1p2,p3p4)非0)
//-----------------------------------------------------------------
double W,H;
int a[],n,pn;
double CUT(Seg seg,Point p[]){
int i,j,tot=;
Point A,B;
A=B=Point(,);
bool s,e;
for(i=;i<pn;i++){//这里A、B交替存储seg与动态凸包p[]的交点,并把新凸包保存在pp中,新的凸包点数保存在tot中
if(!outside(seg,p[i]))pp[tot++]=p[i];//p[i]在射线seg右或上
else {
if(i==&&!outside(seg,p[pn-])){//当前p[i]p[i-1]和seg的交点(当i==0时要特殊处理一下)
B=A;
pp[tot++]=Intersect(seg.s,seg.e,p[i],p[pn-],A);
}
if(i!=&&!outside(seg,p[i-])) {
B=A;
pp[tot++]=Intersect(seg.s,seg.e,p[i],p[i-],A);
}
if(!outside(seg,p[i+])) {//当前p[i]p[i+1]和seg的交点(因为我们已经令p[最后一个的后一个]=p[0]所以不必特殊处理)
B=A;
pp[tot++]=Intersect(seg.s,seg.e,p[i],p[i+],A);
}
}
}
pp[tot]=pp[];//特殊处理尾部
pn=tot;memcpy(st,pp,sizeof(pp));//更新p[]和pn
return dist(A,B);//返回割痕长度
}
int main(){
int i;
while(scanf("%lf%lf",&W,&H)!=EOF){
double ans=1e20;
st[]=st[]=Point(,);//tmp[100]是用来保存原来矩形凸包外四个顶点的,
st[]=Point(,H); //st[100]是切割过程中凸包的顶点
st[]=Point(W,H); //因此对于每种切割方案,刚开始都要将st设为原始矩形凸包,这也是tmp存在的原因
st[]=Point(W,);
memcpy(tmp,st,sizeof(st));
scanf("%d",&n);Seg ts[];
for(i=;i<n;i++) {
scanf("%lf%lf",&p[i].x,&p[i].y);
a[i]=i;//0、1、2.....后面对其全排枚举实现所有切割方法的暴力枚举
}p[n]=p[];
for(i=;i<n;i++) ts[i].s=p[i],ts[i].e=p[i+];
do{
double tlen=;//切割长度
memcpy(st,tmp,sizeof(tmp));
pn=;//pn和st[100]一样是计算过程中的量(对于每种切割方案,其开始要更新为原来的,其过程要变化,pn即凸包st的点数)
for(i=;i<n;i++){//按照获得的全排序列切割
tlen+=CUT(ts[a[i]],st);
}
ans=min(ans,tlen);//求出最小值,保存在ans里
}while(next_permutation(a,a+n));//暴力枚举所有情况next_permutation(a,a+n)是将数组全排列找出
printf("Minimum total length = %.3lf\n",ans);
}
return ;
}
/*
线的交点
1>直线可以用直线上一点P0和方向向量v来表示:直线上所有点P满足P=P0+t*v,其中t为参数;如果已知直线上的2个不同的点A、B,则方向向量
为B-A,所以参数方程为A+(B-A)*t;参数方程可以方便的表示出直线射线和线段,区别仅在于t的范围:直线t无范围,射线t>0,线段t在0~1之间
2>直线交点:设直线分别为P+t*v,Q+t*w,u=PQ,交点在第一条直线上的参数为t1、在第二条直线上的参数为t2,则x、y的坐标可以列出一个方程,
截得:t1=cross(w,u)/cross(v,w),t2=cross(v,u)/cross(v,w),前提要确保分母不为0!!
*/
/*
在STL中,除了next_permutation外,还有一个函数prev_permutation,两者都是用来计算排列组合的函数。
前者是求出下一个排列组合,而后者是求出上一个排列组合。所谓“下一个”和“上一个”,书中举了一个
简单的例子:对序列 {a, b, c},每一个元素都比后面的小,按照字典序列,固定a之后,a比bc都小,c比b大,
它的下一个序列即为{a, c, b},而{a, c, b}的上一个序列即为{a, b, c},同理可以推出所有的六个序列为:
{a, b, c}、{a, c, b}、{b, a, c}、{b, c, a}、{c, a, b}、{c, b, a},其中{a, b, c}没有上一个元素,
{c, b, a}没有下一个元素。
*/

[ACM_几何] Metal Cutting(POJ1514)半平面割与全排暴力切割方案的更多相关文章

  1. poj 1514 Metal Cutting (dfs+多边形切割)

    1514 -- Metal Cutting 一道类似于半平面交的题. 题意相当简单,给出一块矩形以及最后被切出来的的多边形各个顶点的位置.每次切割必须从一端切到另一端,问切出多边形最少要切多长的距离. ...

  2. [ACM_几何] Pipe

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28417#problem/B     本题大意: 给定一个管道上边界的拐点,管道宽为1,求 ...

  3. [ACM_几何] Fishnet

      http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28417#problem/C 本题大意:有一个1X1的矩形,每边按照从小到大的顺序给n ...

  4. [ACM_几何] UVA 11300 Spreading the Wealth [分金币 左右给 最终相等 方程组 中位数]

    Problem A Communist regime is trying to redistribute wealth in a village. They have have decided to ...

  5. [ACM_几何] The Deadly Olympic Returns!!! (空间相对运动之最短距离)

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28235#problem/B 题目大意: 有两个同时再空间中匀速运动的导弹,告诉一个时间以 ...

  6. [ACM_几何] F. 3D Triangles (三维三角行相交)

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28235#problem/A 题目大意:给出三维空间两个三角形三个顶点,判断二者是否有公共 ...

  7. [ACM_几何] Wall

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28417#problem/E 题目大意:依次给n个点围成的一个城堡,在周围建围墙,要求围墙 ...

  8. [ACM_暴力][ACM_几何] ZOJ 1426 Counting Rectangles (水平竖直线段组成的矩形个数,暴力)

    Description We are given a figure consisting of only horizontal and vertical line segments. Our goal ...

  9. [ACM_几何] Transmitters (zoj 1041 ,可旋转半圆内的最多点)

    Description In a wireless network with multiple transmitters sending on the same frequencies, it is ...

随机推荐

  1. Linux C学习笔记06--Tlist使用(编程工具篇)

    为了方便用VIM编程,安装了一个方便的小工具 taglist,下面是taglist使用的一些说明. 常用的taglist配置选项,可以根据自己的习惯进行配置: Tlist_Ctags_Cmd选项用于指 ...

  2. 编程实践中C语言的一些常见细节

    对于C语言,不同的编译器采用了不同的实现,并且在不同平台上表现也不同.脱离具体环境探讨C的细节行为是没有意义的,以下是我所使用的环境,大部分内容都经过测试,且所有测试结果基于这个环境获得,为简化起见, ...

  3. LVS三种工作方式八种算法

    一.集群简介 什么是集群 计算机集群简称集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作.在某种意义上,他们可以被看作是一台计算机.集群系统中的单个计算 ...

  4. jvm中加载类的全过程

    ClassLoader的作用:概括来说就是将编译后的class装载.加载到机器内存中,为了以后的程序的执行提供前提条件. jvm的整个生命周期,如下图所示 加载=>验证=>准备=>解 ...

  5. 01背包问题:POJ3624

    背包问题是动态规划中的经典问题,而01背包问题是最基本的背包问题,也是最需要深刻理解的,否则何谈复杂的背包问题. POJ3624是一道纯粹的01背包问题,在此,加入新的要求:输出放入物品的方案. 我们 ...

  6. 自己随意写了个简单的依赖jquery的轮播图

    //轮播图 function Switcher(obj){ this.box = $(obj.box); this.width = this.box.width(); this.banner = $( ...

  7. 使用 xlrd 模块实现对excel 的读取、excel转json 、excel 转 mysql insert 语句

    #-*- coding:utf-8 -*- # 处理 excel 中的 area 为 Mysql insert 语句 import xlrd, json, codecs, os # data = xl ...

  8. server 2008 IIS 搭建PHP运行环境

    本文以windows server 2008 r2 Enterprise作为操作系统,以IIS为web部署服务组件,配置PHP的服务器端执行环境,其中IIS版本为7.5,PHP版本为5.3. 注意:本 ...

  9. mysql: symbol lookup error: /usr/local/lib/libreadline.so.6: undefined symbol: UP

    Error Symptom: when you run $mysql -u root -p command in the linux you get an error message ” mysql: ...

  10. Fiddler怎么对IPhone手机的数据进行抓包分析

    http://www.cr173.com/html/20064_1.html Fiddler绝对称得上是"抓包神器", Fiddler不但能截获各种浏览器发出的HTTP请求, 也可 ...