输入坑姐啊!!!
因为采用的是离散数学上图论的方法,也就是类似http://blog.csdn.net/zxy_snow/article/details/6581745这个题的方法,这个求蛋糕的块数,也就是这个平面图的面数 - 1.
根据欧拉定理,连通平面图(如果把交点都看做结点,那么肯定是平面图)满足 V - E + R = 2。 其中V是顶点数,E是边数,R是面数。
所以直接找所有的交点(不能重复,我排了下序去重),找边数的话,画图可知,一条线段上有N个交点,那么它就被分成了 N-1份~所以只要这么找就可以了(这点要求必须所有的线段都不重合~!)。
坑姐啊!!!题目上说,The intersections of the cut line and the cake edge are two.而且输入数据都是线段在边上有两点的,所以我以为线段的两个端点一定在矩形的边上的 = = 。。。刚才测试了下,如果不在边上的话,让程序执行while(1); 结果还真TLE了,说明数据线段的两点可能不在边上,坑姐啊!!那么计算交点的时候,得判断这个交点是否在这个矩形内(包括边界)!
还有一点要注意,可能切痕有重叠,所以一定要判断切痕是否出现过 = =。。。而且鉴于切痕端点是随便给的,所以要判断是否共线 = = 而不是判断相等(我没试只判断相等对不对,只试了,它里面肯定有重叠切痕!)
另一种方法,是蓝书上的,http://blog.csdn.net/program_shun/article/details/6589452和这个题解差不多吧,不过蓝书上有证明。(《实用算法分析设计》)。
刚删了自己写的去重的程序,用了unique函数,好方便哈,unique只能去掉相邻重复的元素留下一个,所以必须排序后再用unique,写了下unique的比较函数,这个也比较方便哈,STL好伟大~~
#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> using namespace std; const int MAX = 10; struct point{ double x,y;}; const double eps = 1e-8; bool dy(double x,double y) { return x > y + eps;} // x > y bool xy(double x,double y) { return x < y - eps;} // x < y bool dyd(double x,double y) { return x > y - eps;} // x >= y bool xyd(double x,double y) { return x < y + eps;} // x <= y bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 { return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y); } point p[MAX*MAX]; struct line{ point a,b; void p(double x,double y,double x1,double y1) { a.x = x; a.y = y; b.x = x1; b.y = y1; } }; line l[MAX]; int ee; bool cmp(point a,point b) { if( dd(a.x,b.x) ) return xy(a.y,b.y); return xy(a.x,b.x); } bool cmp1(point a,point b) { return dd(a.x,b.x) && dd(a.y,b.y); } bool onSegment(point a, point b, point c) { double maxx = max(a.x,b.x); double maxy = max(a.y,b.y); double minx = min(a.x,b.x); double miny = min(a.y,b.y); if( dd(crossProduct(a,b,c),0.0) && dyd(c.x,minx) && xyd(c.x,maxx) && dyd(c.y,miny) && xyd(c.y,maxy) ) return true; return false; } bool s2s_inst(point p1,point p2, point p3, point p4) { double d1 = crossProduct(p3,p4,p1); double d2 = crossProduct(p3,p4,p2); double d3 = crossProduct(p1,p2,p3); double d4 = crossProduct(p1,p2,p4); if( xy(d1 * d2,0.0) && xy(d3 * d4,0.0) ) return true; if( dd(d1,0.0) && onSegment(p3,p4,p1) ) return true;//如果不判端点相交,则下面这四句话不需要 if( dd(d2,0.0) && onSegment(p3,p4,p2) ) return true; if( dd(d3,0.0) && onSegment(p1,p2,p3) ) return true; if( dd(d4,0.0) && onSegment(p1,p2,p4) ) return true; return false; } point s2s_inst_p(point u1,point u2,point v1,point v2) { point ans = u1; double t = ((u1.x - v1.x)*(v1.y - v2.y) - (u1.y - v1.y)*(v1.x - v2.x))/ ((u1.x - u2.x)*(v1.y - v2.y) - (u1.y - u2.y)*(v1.x - v2.x)); ans.x += (u2.x - u1.x)*t; ans.y += (u2.y - u1.y)*t; return ans; } void check(point x,int n) { for(int i=0; i<n; i++) if( onSegment(l[i].a,l[i].b,x) ) ee++; } bool chong(point a,point b,int n) { for(int i=0; i<n; i++) if( dd(crossProduct(l[i].a,l[i].b,a),0.0) && dd(crossProduct(l[i].a,l[i].b,b),0.0) ) return true; return false; } int main() { l[0].p(0,0,1000,0); l[1].p(0,0,0,1000); l[2].p(0,1000,1000,1000); l[3].p(1000,0,1000,1000); int n; double a,b,c,d; while( ~scanf("%d",&n) && n ) { int cnt = 0; ee = 0; int cc = 4; while( n-- ) { scanf("%lf%lf%lf%lf",&a,&b,&c,&d); point aa,bb; aa.x = a; aa.y = b; bb.x = c; bb.y = d; if( !chong(aa,bb,cc) ) l[cc++].p(a,b,c,d); } n = cc; for(int i=0; i<n; i++) for(int k=i+1; k<n; k++) if( s2s_inst(l[i].a,l[i].b,l[k].a,l[k].b) ) { point pp = s2s_inst_p(l[i].a,l[i].b,l[k].a,l[k].b); if( dyd(pp.x,0.0) && xyd(pp.x,1000.0) && dyd(pp.y,0.0) && xyd(pp.y,1000.0) ) p[cnt++] = pp; } sort(p,p+cnt,cmp); int nn = unique(p,p+cnt,cmp1) - p;// unique函数好好用~~ for(int i=0; i<nn; i++) check(p[i],n); // 找边的数目 int ans = ee - n - nn + 1; printf("%d\n",ans); } return 0; }