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