题目链接: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;
}