• 【题解】切割多边形 [SCOI2003] [P4529] [Bzoj1091]


    【题解】切割多边形 [SCOI2003] [P4529] [Bzoj1091]

    传送门:切割多边形 ( ext{[SCOI2003] [P4529]}) ( ext{[Bzoj1091]})

    【题目描述】

    给出一个 (Mx*My) ((0 < Mx,My < 500)) 的矩形,现要用 (n) ((3 leqslant n leqslant 8)) 条直线依次对其进行切割,将它变成凸 (n) 边形,每次切割的长度为该直线在剩下的矩形内部的部分的长度,求最短的切割线总长度。

    【分析】

    一道计算几何膜您题。

    由于 (n) 比较小,可以 (O(n!)) 枚举切割线的顺序,最后计算总长度取最小值就行了。

    但有个非常麻烦的问题:如何求每次加入直线的切割线长度?

    考虑用一个栈储存当前已经加入的直线(上下左右四个边界会在最初时加入),如果现在要加入直线 (p_1-p_2)(这里为方便描述,设 (p_1) 在左边,(p_2) 在右边),先求出它与栈中所有直线的交点,然后在这些交点中分别找到:(p_1) 左边距离 (p_1) 最近的点 (ans_1)(p_2) 右边距离 (p_2) 最近的点(ans_2),易知 (len(ans_1,ans_2)) 即为当次切割线长度。

    图就不画了,自己领会吧。。。

    【Code】

    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define LD double
    #define LL long long
    #define Re register int
    #define Vector Point
    using namespace std;
    const int N=20;
    const LD eps=1e-9,inf=1e9;
    inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}//处理精度
    inline LD Abs(LD a){return a*dcmp(a);}//取绝对值
    struct Point{
        LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
        inline void in(){scanf("%lf%lf",&x,&y);}
        inline void out(){printf("%.2lf %.2lf
    ",x,y);}
    }p1,p2,p3,p4,P[N];
    struct Line{
        Point a,b;int id;LD k;Line(Point X=Point(0,0),Point Y=Point(0,0),int ID=0,LD K=0){a=X,b=Y,id=ID,k=K;}
        inline void sakura(){k=(!dcmp(a.x-b.x))?0.0:(a.y-b.y)/(a.x-b.x);}
        inline bool operator<(Line O)const{return k<O.k;}
    }L[N],Q[N];
    inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}//点积
    inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}//叉积
    inline LD Len(Vector a){return sqrt(Dot(a,a));}//模长
    inline Point operator+(Point a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
    inline Vector operator-(Point a,Point b){return Vector(a.x-b.x,a.y-b.y);}
    inline Vector operator*(Vector a,LD b){return Vector(a.x*b,a.y*b);}
    inline Point cross_LL(Point a,Point b,Point c,Point d){//两直线AB,CD的交点
        Vector x=b-a,y=d-c,z=a-c;
        return a+x*(Cro(y,z)/Cro(x,y));//点A加上向量AF
    }
    int n,t,a[N],vis[N];LD Mx,My,Ans=inf;
    inline void dfs(Re g,LD ans){
        if(g>n){Ans=min(Ans,ans);return;}
        for(Re i=1;i<=n;++i)
            if(!vis[i]){
                Point p1=L[i].a,p2=L[i].b,ans1=Point(inf,inf),ans2=Point(inf,inf);
                //ans1:在p2-p1延长线上距离p1最近的点
                //ans2:在p1-p2延长线上距离p2最近的点
                for(Re j=1;j<=t;++j){
                    Point b=cross_LL(p1,p2,Q[j].a,Q[j].b);//获取直线L[i]与Q[i]的交点b
                    if(dcmp(Len(p1-b)-Len(p2-b))<0&&dcmp(Len(p1-ans1)-Len(p1-b))>0)ans1=b;//如果 len(b,p1)<len(b,p2) 且 len(p1,b)<len(p1,ans1)
                    if(dcmp(Len(p2-b)-Len(p1-b))<0&&dcmp(Len(p2-ans2)-Len(p2-b))>0)ans2=b;//如果 len(b,p2)<len(b,p1) 且 len(p2,b)<len(p2,ans2)
                }
                vis[i]=1,Q[++t]=L[i];
                dfs(g+1,ans+Len(ans1-ans2));//加上len(ans1,ans2)
                vis[i]=0,--t;
            }
    }
    int main(){
    //  freopen("123.txt","r",stdin);
        scanf("%lf%lf%d",&Mx,&My,&n);
        for(Re i=1;i<=n;++i)P[i].in();
        for(Re i=1;i<=n;++i)L[i]=Line(P[i],P[i<n?i+1:1],i);//获取n条直线
        p1=Point(0,0),p2=Point(0,My),p3=Point(Mx,My),p4=Point(Mx,0);//四个顶点
        Q[++t]=Line(p1,p2),Q[++t]=Line(p2,p3),Q[++t]=Line(p3,p4),Q[++t]=Line(p4,p1);//先将四个边界入队
        dfs(1,0.0);
        printf("%.3lf
    ",Ans);
    }
    
  • 相关阅读:
    Flask 开启跨域
    pandas to dict
    mongodb 聚合查询
    flask 获取请求参数
    CSS dppx详解
    用CSS做出漂亮的字体动画
    VMware虚拟主机安装完成后连接不上网络
    wokerman中自定义协议的使用和测试
    使用workerman写一个小的聊天室
    telnet不能使用怎么办?
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/12116733.html
Copyright © 2020-2023  润新知