FZU 1015 土地划分

来源:互联网 发布:华为ip地址mac绑定 编辑:程序博客网 时间:2024/04/29 18:58

题目链接: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 100struct point{    int x;    int y;};struct Vector{    point s;    point e;};point  p[N];Vector v[N];#define  EPS 1e-6double 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;}