FZU 1015 土地划分

题目链接:http://acm.fzu.edu.cn/problem.php?pid=1015


解题思路:就是求 n 条线段能将矩形划分成多少个区域。  

        首先分析直线划分区域的情况,根据已知的结论:平面上 n 条直线最多可以将平面分成 f ( n ) 个区域,  其中 f ( n )  =  ( n * n + n + 2 ) / 2。

        我们用数学归纳法证明一下:当 n = 1 时,f ( n ) = 2显然成立,即一条直线把平面分成两个区域。假设对于所有的 n < k 的 n,均有

         f ( n )  =  ( n * n + n + 2 ) / 2。考虑当 n = k,新的直线 l 最多可以和原来的 n-1 条直线有 n - 1 个交点,这 n - 1 个交点将直线分成了 n 段,

        其中 n - 2 段为线段,两段为射线。这 n 段线将其所在的 n 个区域一分为二,这样就增加了 n 个区域,所以 f ( n ) = f ( n - 1) + n。

         再由归纳假设 f ( n - 1 ) = ( ( n-1 ) * ( n - 1 ) + ( n - 1 ) + 2 ) / 2,

         因而有: f ( n ) = ( ( n-1 ) * ( n - 1 ) + ( n - 1 ) + 2 ) / 2 + n = ( n * n + n + 2 ) / 2。所以对所有的正整数 n 都有  f ( n ) = ( n * n + n + 2 ) / 2。


          以上证明的关键部分是归纳出 f ( n ) =  f ( n - 1 ) + n  的过程。因为线段划分矩形问题与直线划分平面的问题是类似的,所以解题思路也是类似的。

          设 f ( n ) 为前 n 条输入的线段将矩形分成区域的个数,1 <= n <= L ,L为线段总数。边界:f ( 1 ) = 2,即一条线段将矩形分成两个区域。

          递推:假设已经处理了 n - 1 条线段,新线段为 l ,它和已有的 n - 1 条线段交有 t ' ( n )  个交点。注意:有些交点在矩形的边界上,

          这些交点也是线段的端点,必须将其排除,于是剩下 t ( n ) 个交点。 由于题目限定“任意三点不共线”,因此这些交点将 l 分成 t ( n ) + 1 条线段。

          这 t ( n ) + 1 条线段将所在区域一分为二,这样就增加了 t ( n ) + 1 个区域,所以 f ( n ) =  f ( n - 1 ) + t ( n )  + 1,则得到 f ( n ) 的递推式;

          f ( n ) = f ( 1 ) + [  t ( 2) + t ( 3 ) +… + t  ( n )  ] + n - 1 。令输入的 L 条线段之间不在矩形边上的交点个数为 T ,则 T =  t ( 2) + t ( 3 ) +… + t  ( n )。

          所以:f ( L ) = f ( 1 ) + T + L +1,也就是说问题的答案就是线段的条数加上交点的个数再加上 1 。其中L是已知的,问题转化为求 L 条线段之间

          交点(不在矩形边界上)的个数。

代码如下

#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
#define  N 100
struct point{
    int x;
    int y;
};

struct Vector{
    point s;
    point e;
};

point  p[N];
Vector v[N];

#define  EPS 1e-6

double multi(point p1,point p2,point p0)
{
     return ((p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x));
}
int  Equal_Point(point p1,point p2)
{
     return(abs(p1.x-p2.x)<EPS && abs(p1.y-p2.y)<EPS);
}
bool Isinside(Vector v1,Vector v2)
{
     if(max(v1.s.x,v1.e.x)>=min(v2.s.x,v2.e.x) &&
        max(v2.s.x,v2.e.x)>=min(v1.s.x,v1.e.x) &&
        max(v1.s.y,v1.e.y)>=min(v2.s.y,v2.e.y) &&
        max(v2.s.y,v2.e.y)>=min(v1.s.y,v1.e.y) &&
        multi(v2.s,v1.e,v1.s) * multi(v1.e,v2.e,v1.s) >=0 &&
        multi(v1.s,v2.e,v2.s) * multi(v2.e,v1.e,v2.s) >=0)
          return true;
     return false;

}

bool Across(Vector v1,Vector v2)
{
     if(Isinside(v1,v2) && !Equal_Point(v1.e,v2.s) && !Equal_Point(v1.s,v2.s)
        && !Equal_Point(v1.e,v2.e) && !Equal_Point(v1.s,v2.e))
            return true;
    return false;
}

int  main()
{
     int w,h;
     while(~scanf("%d%d",&w,&h) && w+h)
     {
          int l;
          scanf("%d",&l);
          l++;
          for(int i=0;i<l;i++)
          {
                scanf("%d %d",&p[i].x,&p[i].y);
                if(i==0)
                {
                       v[i].s.x=p[i].x;
                       v[i].s.y=p[i].y;
                }
                else
                {
                       v[i].e.x=p[i].x;
                       v[i].e.y=p[i].y;
                       v[i+1].s.x=p[i].x;
                       v[i+1].s.y=p[i].y;

                }

          }
          int sum=0;
          for(int i=0;i<l;i++)
          {
                for(int j=i+1;j<l;j++)
                {
                      if(Across(v[i],v[j]))
                           sum++;
                }
          }
          sum+=(l-1) + 1;
          printf("%d\n",sum);
     }
     return 0;
}


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值