fzu 1015 土地划分(判断线段相交+求出交点+找规律)

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

 Problem 1015 土地划分

Accept: 714    Submit: 1675
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

在Dukeswood这块土地上生活着一个富有的农庄主和他的几个孩子。在他临终时,他想把他的土地分给他的孩子。他有许多农场,每个农场都是一块矩形土地。他在农场地图上划上一些直线将矩形分成若干块。当他划直线时,他总是从矩形边界上的某一点划到另一个矩形边界上的点,这条线的结束点将成为下一条线的起始点。他划线时从不会让任三线共点。例如图1是某一种划分结果。


图1

划分的起始点和结束点均以五角星标记。当他完成划分后,他想要数一下划出的土地的块数以确保每个孩子都有一块地。例如,图1中土地被划分成18块。然而这个庄主由于年迈常会数错,因而他寻求你的帮助。

请写一个程序,输入原来的土地尺寸及线段的位置,输出划分出的土地块数。

 Input

输入文件有多组数据组成。每组数据格式如下:
第一行输入地图的宽度w (1<=w<=1000)和高度 h (1<=h<=1000),均为整数。
第二行输入线段数L (1<=L<=50)。
以下L+1行每行一个整数坐标(Xi,Yi),庄主划的线段为(Xi,Yi)-(Xi+1,Yi+1),i=1,2,…,L。当然(Xi,Yi)必定在矩形的边界上。
最后一组数据w=h=0,标志文件结束,不需要处理。

 Output

对于给定的输入,输出一行仅含一个数,即划分出的土地块数。

 Sample Input

18 12

8

2 0

6 12

10 0

18 9

15 12

0 6

14 0

10 12

0 9

7 6

6

2 0

5 6

7 3

0 3

3 0

3 6

0 5

0 0

 Sample Output

18

11

/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。/。

看到此题,可联想到组合几何中的一个问题,求平面上n条直线最多可以将平面分成多少块

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

实际上,重点是讨论如何得出这个结论的过程

方法————数学归纳法

当n=1时,f(1)=(1^2+1+2)/2=2显然成立,即一条直线把平面分成两个区域。

-----------------------------------------------------------------------------------

假设,对所有的n<k的n,均有f(n)=(n^2+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)^2+(n-1)+2)/2,因而有:

f(n)=((n-1)^2+(n-1)+2)/2+n=(n^2+n+2)/2

因此,对所有的正整数n,均有f(n)=(n^2+n+2)/2

-----------------------------------------------------------------------------------

具体推导过程看这里吧:http://wenku.baidu.com/view/15733b0b79563c1ec5da71cf.html

经过推导,可以得出结论,f(L)=1+T+L

就是不在矩形边上的交点个数T+线段的条数L+1即为答案

下面给出代码:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <math.h>
  5 #include <iostream>
  6 #include <algorithm>
  7 #define eps 1e-6
  8
  9 struct point
 10 {
 11     double x,y;
 12 };
 13
 14 struct beline
 15 {
 16     point a,b;
 17 };
 18
 19 using namespace std;
 20
 21 point p[5000];
 22
 23 bool dy(double x,double y)
 24 {
 25     return x > y+eps;
 26 }
 27 bool xy(double x,double y)
 28 {
 29     return x < y-eps;
 30 }
 31 bool xyd(double x,double y)
 32 {
 33     return x < y+eps;
 34 }
 35 bool dyd(double x,double y)
 36 {
 37     return x > y-eps;
 38 }
 39 double dd(double x,double y)
 40 {
 41     return fabs(x-y) < eps;
 42 }
 43
 44 double crossProduct(point a,point b,point c)
 45 {
 46     return (c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x);
 47 }
 48
 49 bool onSegment(point a,point b,point c)
 50 {
 51     double maxx=max(a.x,b.x);
 52     double maxy=max(a.y,b.y);
 53     double minx=min(a.x,b.x);
 54     double miny=min(a.y,b.y);
 55     if(dd(crossProduct(a,b,c),0.0)&&dyd(c.x,minx)&&xyd(c.x,maxx)
 56         &&dyd(c.y,miny)&&xyd(c.y,maxy))
 57         return true;
 58     return false;
 59 }
 60
 61 bool segIntersect(point p1,point p2,point p3,point p4)
 62 {
 63     double d1 = crossProduct(p3,p4,p1);
 64     double d2 = crossProduct(p3,p4,p2);
 65     double d3 = crossProduct(p1,p2,p3);
 66     double d4 = crossProduct(p1,p2,p4);
 67     if(xy(d1*d2,0.0)&&xy(d3*d4,0.0))
 68         return true;
 69     if(dd(d1,0.0)&&onSegment(p3,p4,p1))
 70         return true;
 71     if(dd(d2,0.0)&&onSegment(p3,p4,p2))
 72         return true;
 73     if(dd(d3,0.0)&&onSegment(p1,p2,p3))
 74         return true;
 75     if(dd(d4,0.0)&&onSegment(p1,p2,p4))
 76         return true;
 77     return false;
 78 }
 79
 80 point intersectpoint(beline u,beline v)
 81 {
 82     point ans=u.a;
 83     double t = ((u.a.x-v.a.x)*(v.a.y-v.b.y)-(u.a.y-v.a.y)*(v.a.x-v.b.x))/
 84     ((u.a.x-u.b.x)*(v.a.y-v.b.y)-(u.a.y-u.b.y)*(v.a.x-v.b.x));
 85     ans.x+=(u.b.x-u.a.x)*t;
 86     ans.y+=(u.b.y-u.a.y)*t;
 87     return ans;
 88 }
 89 int main()
 90 {
 91     int n,m,i,j,k;
 92     beline li[55];
 93     while(scanf("%d%d",&n,&m)!=EOF&&n||m)
 94     {
 95         scanf("%d",&k);
 96         for(i=0;i<=k;i++)
 97         {
 98             scanf("%lf%lf",&p[i].x,&p[i].y);
 99         }
100         for(i=0;i<k;i++)
101         {
102             li[i].a.x=p[i].x;
103             li[i].a.y=p[i].y;
104             li[i].b.x=p[i+1].x;
105             li[i].b.y=p[i+1].y;
106         }
107
108         int sum=0;
109         for(i=0;i<k;i++)
110         {
111             for(j=i+1;j<k;j++)
112             {
113                 if(segIntersect(li[i].a,li[i].b,li[j].a,li[j].b))
114                 {
115                     point tmp;
116                     tmp=intersectpoint(li[i],li[j]);
117                     if(dy(tmp.x,0.0)&&xy(tmp.x,(double)n)&&dy(tmp.y,0.0)&&xy(tmp.y,(double)m))
118                     {
119                         sum++;
120                     }
121                 }
122             }
123         }
124         printf("%d\n",sum+k+1);
125     }
126     return 0;
127 }

fzu 1015 土地划分(判断线段相交+求出交点+找规律)

时间: 2025-01-04 19:15:54

fzu 1015 土地划分(判断线段相交+求出交点+找规律)的相关文章

两线段相交求交点

算法一 #include #include #include struct POINT { int x; int y; }; bool IsLineSegmentCross(POINT pFirst1, POINT pFirst2, POINT pSecond1, POINT pSecond2) { //每个线段的两点都在另一个线段的左右不同侧,则能断定线段相交 //公式对于向量(x1,y1)->(x2,y2),判断点(x3,y3)在向量的左边,右边,还是线上. //p=x1(y3-y2)+x2

hdu 1086(判断线段相交)

传送门:You can Solve a Geometry Problem too 题意:给n条线段,判断相交的点数. 分析:判断线段相交模板题,快速排斥实验原理就是每条线段代表的向量和该线段的一个端点与 另一条线段的两个端点构成的两个向量求叉积,如果线段相交那么另一条线段两个端点必定在该线段的两边,则该线段代表的向量必定会顺时针转一遍逆时针转一遍,叉积必定会小于等于0,同样对另一条线段这样判断一次即可. #include <algorithm> #include <cstdio>

HDU 1086 You can Solve a Geometry Problem too(判断线段相交)

题目地址:HDU 1086 就这么一道仅仅判断线段相交的题目写了2k多B的代码..是不是有点浪费...但是我觉得似乎哪里也优化不了了.... 判断线段相交就是利用的叉积.假如现在两条线段分别是L1和L2,先求L1和L2两个端点与L1的某个端点的向量的叉积,如果这两个的叉积的乘积小于0的话,说明L1在是在L2两个端点之间的,但此时并不保证一定相交.此时需要用同样的方法去判断L2是否在L1的两个端点之间,如果L2也在L1的两个端点之间的话,那就足以说明L1与L2相交.但是这题还需要判断是否端点也相交

HDU1558 - Segment set 并查集 + 判断线段相交

HDU1558 - Segment set: http://acm.hdu.edu.cn/showproblem.php?pid=1558 题目大意: 输入一些线段的端点坐标,若两线段相交,则把他们合并成一个集合,输入数据里会有k,问和k线段相交的线段的数目(包括自己) 思路: 每次输入一条线段,都从头扫描一次. 找出之前输入的线段里面,所有和其相交的线段,并且合并(合并用的是线段的ID). 就是: 并查集 + 判断线段相交 代码: #include <iostream> #include &

POJ 2826 An Easy Problem? 判断线段相交

POJ 2826 An Easy Problem?! -- 思路来自kuangbin博客 下面三种情况比较特殊,特别是第三种 G++怎么交都是WA,同样的代码C++A了 #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const double eps = 1e-8;

POJ2653 Pick-up sticks 判断线段相交

POJ2653 判断线段相交的方法 先判断直线是否相交 再判断点是否在线段上 复杂度是常数的 题目保证最后答案小于1000 故从后往前尝试用后面的线段 "压"前面的线段 排除不可能的答案 就可以轻松AC了. #include<iostream> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<algorit

【POJ 2653】Pick-up sticks 判断线段相交

一定要注意位运算的优先级!!!我被这个卡了好久 判断线段相交模板题. 叉积,点积,规范相交,非规范相交的简单模板 用了“链表”优化之后还是$O(n^2)$的暴力,可是为什么能过$10^5$的数据? #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> #define N 100005 using namespace std; struct Point { double x

判断线段相交

1 float cross(const Point &point0, const Point &point1) 2 { 3 return point0.first * point1.second - point0.second * point1.first; 4 } 5 6 bool isLineIntersect(const Point &point0, const Point &point1, const Point &point2, const Point &

【C语言】不使用循环和判断语句,求出1-100之间所有数的和

//不使用循环和判断语句,求出1-100之间所有数的和 #include <stdio.h> int fun(int n, int *sum) { *sum = *sum + n; (n--) && (fun(n, sum)); return n; } int main() { int n = 100; int sum = 0; fun(n, &sum); printf("%d\n", sum); return 0; } <img src=&q