BZOJ 1091([SCOI2003]分割多边形-分割直线)

1091: [SCOI2003]分割多边形

Time Limit: 1 Sec  Memory Limit: 162 MB

Submit: 223  Solved: 82

[Submit][Status]

Description

有一个凸p边形(p<=8)。我们希望通过分割得到它。一開始的时候,你有一个n*m的矩形,即它的四角的坐标分别为(0,0), (0,m), (n,0), (n,m)。每次你能够选择一条直线把当前图形分割成两部分,保留当中一个部分(还有一部分扔掉)分割线的长度为此直线在多边形内部的部分的长度。求出最短的分割线总长度。

以下是一个样例。我们须要得到中间的多边形。

分别沿着直线1,2,3。4进行分割就可以,得到中间的四边形。

Input

第一行有两个整数n, m(0 < n,m < 500),第二行为一个整数p(3<=p<=8)。

下面p行每行为两个整数x, y(0 < x < n, 0 < y < m),为按顺时针给出的各顶点坐标。数据保证多边形的是凸的,无三点共线。输入数据无错误。

Output

仅一行,为最短分割线的总长度。四舍五入到小数点后3位。同意有0.001的误差。

Sample Input

100 100

4

80 80

70 30

20 20

20 80

Sample Output

312.575

HINT

例子相应于图中给出的例子。

Source

直接把多边形伸长成2点都在矩形上的线段,这种话每次取时把之前的线段割一下。

注意伸长时保证向量方向

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (1000000007)
#define MP make_pair
#define MAXP (500+10)
#define MAXN (500+10)
#define MAXM (500+10)
#define eps (1e-6)
long long mul(long long a,long long b){return (a*b)%F;}
long long add(long long a,long long b){return (a+b)%F;}
long long sub(long long a,long long b){return (a-b+(a-b)/F*F+F)%F;}
typedef long long ll;
int n,m,p;
double sqr(double x){return x*x;}
int dcmp(double a,double b=0){if (fabs(a-b)<=eps) return 0;else if (a<b) return -1;return 1;}
struct P
{
    double x,y;
    P(){}
    P(double _x,double _y):x(_x),y(_y){}
    friend istream& operator>>(istream& cin,P &a){cin>>a.x>>a.y;return cin;}
    friend ostream& operator<<(ostream& cout,P &a){cout<<a.x<<‘ ‘<<a.y;return cout;}
    friend bool operator==(P a,P b){return dcmp(a.x,b.x)==0&&dcmp(a.y,b.y)==0;    }
}a[MAXP];
struct V
{
    double x,y;
    V(){}
    V(double _x,double _y):x(_x),y(_y){}
    V(P a,P b):x(b.x-a.x),y(b.y-a.y){}
    friend V operator*(double a,V b){return V(a*b.x,a*b.y);}
    friend V operator-(P a,P b){return V(b.x-a.x,b.y-a.y); }
    friend double operator*(V a,V b){return a.x*b.y-a.y*b.x;}
    friend double operator^(V a,V b){return a.x*b.x+a.y*b.y;}
    friend P operator+(P a,V b){return P(a.x+b.x,a.y+b.y);    }
    friend double dis2(V a){return sqr(a.x)+sqr(a.y);    }
};
struct L
{
    P p;
    V v;
    L(){}
    L(P _A,V _B):p(_A),v(_B){}
    friend bool parallel(L a,L b) {return (dcmp(a.v.x*b.v.y,a.v.y*b.v.x))==0;}
    friend P intersect(L a,L b) //直线交点
    {
        V &v=a.v,&w=b.v,u=V(b.p,a.p);
        double t=(w*u)/(v*w);
        P c=a.p+t*v; return c;
    }
    friend bool inleft(P a,L b){return dcmp(b.v*V(b.p,a))>=0;    }
    void print(){cout<<p.x<<‘ ‘<<p.y<<‘ ‘<<v.x<<‘ ‘<<v.y<<endl;    }
}l[MAXP],lrec[4];
bool inrec(P a){return (dcmp(a.x)>=0&&dcmp(a.x,n)<=0&&dcmp(a.y)>=0&&dcmp(a.y,m)<=0);}
L through_rec_line(L l)
{
    int siz=0;P st[3];
    if (dcmp(l.v.x)==0) return L(P(l.p.x,l.v.y>0?0:m),V(0,(l.v.y>0?1:-1)*m));
    if (dcmp(l.v.y)==0) return L(P(l.v.x>0?0:n,l.p.y),V((l.v.x>0?1:-1)*n,0)); //至此保证不平行坐标系
    Rep(i,4)
    {
        if (parallel(lrec[i],l)) continue;
        st[++siz]=intersect(lrec[i],l);
        if (!inrec(st[siz])) siz--;
        if (siz==2)
        {
            if (st[1]==st[2]) siz--;
            else
            {
                V a=V(st[1],st[2]);
                if (dcmp(a^l.v)<0) return L(st[2],V(st[2],st[1]));
                return L(st[1],a);
            }
        }
    }
}
bool b[MAXP]={0};
double ans=1e300;
int cut_list[MAXN];
void dfs(double tot,int siz)
{
    if (tot>ans) return;
    if (siz==p)
    {
    //  Rep(i,siz) cout<<cut_list[i]<<‘ ‘;printf("%.3lf\n",ans);
        ans=min(ans,tot);
        return;
    }

    /*
    if (siz==2)
    {
        if (cut_list[0]==2&&cut_list[1]==1)
        {
            cout<<‘ ‘;
        }
    }*/

    For(i,p)
        if (!b[i])
        {
            L x=through_rec_line(l[i]);
            For(j,p)
                if (!parallel(l[j],x)&&b[j])
                {
                    P p=intersect(x,l[j]);
                    if (dcmp(V(p,x.p)^V(p,x.p+x.v))<0)
                    {
                        if (!inleft(x.p,l[j])) x=L(p,V(p,x.p+x.v));
                        else if (!inleft(x.p+x.v,l[j])) x=L(x.p,V(x.p,p));
                    }
                }
            b[i]=1;
            cut_list[siz]=i;
        /*
            Rep(j,siz) printf("\t");
            cout<<i<<endl;
            printf("%.3lf\n",tot+sqrt(dis2(x.v)));
          */
            dfs(tot+sqrt(dis2(x.v)),siz+1);
            b[i]=0;
        }
}
int main()
{
//  freopen("bzoj1091.in","r",stdin);
//  freopen("bzoj1091.out","w",stdout);

    cin>>n>>m>>p;
    ForD(i,p) cin>>a[i];memcpy(a+p+1,a+1,sizeof(P)*p);
    For(i,p) l[i]=L(a[i],V(a[i],a[i+1]));memcpy(l+p+1,l+1,sizeof(L)*p);

    lrec[0]=L(P(0,0),V(n,0)),lrec[1]=L(P(n,0),V(0,m)),lrec[2]=L(P(n,m),V(-n,0)),lrec[3]=L(P(0,m),V(0,-m));
    For(i,p) l[i]=through_rec_line(l[i]); 

//  For(i,p) l[i].print();

    dfs(0,0);

    printf("%.3lf\n",ans);
    return 0;
}
时间: 2024-10-14 17:03:16

BZOJ 1091([SCOI2003]分割多边形-分割直线)的相关文章

BZOJ 1091([SCOI2003]切割多边形-切割直线)

1091: [SCOI2003]切割多边形 Time Limit: 1 Sec  Memory Limit: 162 MB Submit: 223  Solved: 82 [Submit][Status] Description 有一个凸p边形(p<=8),我们希望通过切割得到它.一开始的时候,你有一个n*m的矩形,即它的四角的坐标分别为(0,0), (0,m), (n,0), (n,m).每次你可以选择一条直线把当前图形切割成两部分,保留其中一个部分(另一部分扔掉)切割线的长度为此直线在多边形

(转)数据库表分割技术浅析(水平分割/垂直分割/库表散列)

数据库表分割技术包含以下内容:水平分割/垂直分割/库表散列.接下来将对以上分割进行详细介绍,感兴趣的朋友可以了解下,对你日后维护数据库是很有帮助的 一.水平分割 什么是水平分割?打个比较形象的比喻,在食堂吃饭的时候,只有一个窗口,排队打饭的队伍太长了,都排成S型了,这时容易让排队的人产生焦虑情绪,容易产生混乱,这时一个管理者站出来,增加多个打饭窗口,把那条长长的队伍拦腰截断成几队.更形象一点的理解,你拿一把“手术刀”,把一个大表猛的切了几刀,结果这个大表,变成了几个小表. 水平分割根据某些条件将

C 语言 字符串命令 strstr()的用法 实现将原字符串以分割串分割输出【转】

本文转载自;http://www.cnblogs.com/easyfrog/archive/2011/12/26/C_strstr_split_string.html C 语言 字符串命令 strstr()的用法 实现将原字符串以分割串分割输出 strstr() 命令是在原字符串中查找指定的字符串第一次出现的地址,用这个特性可以实现字符的分割,判断是否包涵等功能: 下面的这个例子是实现 字符串以分割串分割输出: 1 #include <stdio.h> 2 #include <strin

(转载)数据库表分割技术浅析(水平分割/垂直分割/库表散列)

一.数据库表分割技术 数据库表分割技术包含以下内容: 水平分割 垂直分割 库表散列 1.1.水平分割 什么是水平分割?打个比较形象的比喻,在食堂吃饭的时候,只有一个窗口,排队打饭的队伍太长了,都排成S型了,这时容易让排队的人产生焦虑情绪,容易产生混 乱,这时一个管理者站出来,增加多个打饭窗口,把那条长长的队伍拦腰截断成几队.更形象一点的理解,你拿一把“手术刀”,把一个大表猛的切了几刀,结果这个大表,变成了几个小表. 水平分割根据某些条件将数据放到两个或多个独立的表中.即按记录进分分割,不同的记录

【bzoj 3675】[Apio2014]序列分割

Description 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序列,小H需要重复k次以下的步骤: 1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的序列--也就是一开始得到的整个序列): 2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新序列. 每次进行上述步骤之后,小H将会得到一定的分数.这个分数为两个新序列中元素和的乘积.小H希望选择一种最佳的分割方式,使得k轮之后,小

【BZOJ】1044: [HAOI2008]木棍分割 二分+区间DP

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1044 Description 有n根木棍, 第i根木棍的长度为Li,n根木棍依次连结了一起, 总共有n-1个连接处. 现在允许你最多砍断m个连接处, 砍完后n根木棍被分成了很多段,要求满足总长度最大的一段长度最小, 并且输出有多少种砍的方法使得总长度最大的一段长度最小. 并将结果mod 10007... Input 输入文件第一行有2个数n,m. 接下来n行每行一个正整数Li,表示第i根木棍

bzoj1091: [SCOI2003]切割多边形

Description 有一个凸p边形(p<=8),我们希望通过切割得到它.一开始的时候,你有一个n*m的矩形,即它的四角的坐标分别为(0,0), (0,m), (n,0), (n,m).每次你可以选择一条直线把当前图形切割成两部分,保留其中一个部分(另一部分扔掉)切割线的长度为此直线在多边形内部的部分的长度.求出最短的切割线总长度.下面是一个例子.我们需要得到中间的多边形. 分别沿着直线1,2,3,4进行切割即可,得到中间的四边形. Input 第一行有两个整数n, m(0 < n,m &l

Java-使用IO流对大文件进行分割和分割后的合并

有的时候我们想要操作的文件很大,比如:我们想要上传一个大文件,但是收到上传文件大小的限制,无法上传,这是我们可以将一个大的文件分割成若干个小文件进行操作,然后再把小文件还原成源文件.分割后的每个小文件的类型可以自己定义. 一下是我编写的一个大文件的分割和合并的代码: package com.lym; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; impor

BZOJ 1090: [SCOI2003]字符串折叠( 区间dp )

按照题意dp...dp(l, r) = min{ dp(l, x) + dp(x+1, r) , 折叠(l, r) } 折叠(l, r)我是直接枚举长度然后哈希判.. -------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef unsigned long long ull; const int maxn = 109; con