1. 程式人生 > >FZU 1015 土地劃分

FZU 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;
}