自己写得手忙脚乱的,而标程好简洁。
我发现这种情况有一个特点,那就是我总想着一次性搞定一些东西,而不是分两次。比如此题,我总想着一次性求出e与v,而不是先求出v再慢慢求e。
可能是因为做算法题做习惯了,总是追求高效率,但是自己追求高效率的方法是不对的,总是希望一次性求出所有东西。事实上这样效率不但没有显著提高,还会把程序结构弄得乱七八糟,从而导致出现各种奇奇怪怪的bug,然后也很难看清思路与检查。其实说了那么多都没说到本质,只不过是因为自己不会做或者对这类题型不够熟练,所以才会走上弯路,如果自己完全会做或者非常熟悉这类问题,便不会出现这种糟糕的情况了。还要多加练习。
分析
很容易想到要用平面图的欧拉定理,所以要想办法求v和e。
v其实挺好求的,就是枚举所有线段,如果相交就求出交点,然后放进set里就好了。但是会有精度问题,需要用到eps并重载==解决,而set只能重载<而不能重载==,所以要另谋出路。其实出路很多,可以像书上那样重载==和<后用sort+unique大法(这简直就是一个set呀)。也可以写一写查找表来搞(顺序表估计会超时啦)。但是该如何求e呢,我就总想着在求v的时候顺便求出e,然后也是没想清楚就开始写代码(大忌啊,未证明正确性就开始写代码==浪费时间),然后就各种错啊,然后就不会啦。事实上的话很难在点和边上找到比较明确且简洁的关系啦,这个点是端点相交啊还是规范相交啊,好多个边都交在一个点上怎么办啊,其中有些又是规范相交有些又是端点相交,端点相交还要细分呢。。怎么搞得过来呀。事实上有更霸气的解决方法啦,你不是都把所有点都找出来了吗,那就枚举所有点和边,单纯的考虑一个点和一个边的话,是不是就很好判断边是如何被点分隔的了呢?所以枚举一遍统计一下就好了,至少思路上轻松太多,而且时间复杂度也能承受呀,就O(n^2)*O(n)=O(n^3)完全可以接受的。一看这道题的数据范围就能感觉到是O(n^3)的题啦。如果只用到O(n^2)的算法不觉得奇怪吗。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 300 + 10;
struct Point
{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator - (Point A,Point B)
{
return Vector(A.x-B.x,A.y-B.y);
}
Point operator + (Point A,Vector B)
{
return Point(A.x+B.x,A.y+B.y);
}
Vector operator * (Point A,double t)
{
return Vector(A.x*t,A.y*t);
}
bool operator < (Point A,Point B)
{
return A.x<B.x||(A.x==B.x&&A.y<B.y);
}
double Dot(Vector A,Vector B)
{
return A.x*B.x+A.y*B.y;
}
double Cross(Vector A,Vector B)
{
return A.x*B.y-A.y*B.x;
}
Point GetInterSection(Point P,Vector v,Point Q,Vector w)
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
const double eps = 1e-10;
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
bool operator == (Point A,Point B)
{
return dcmp(A.x-B.x)==0&&dcmp(A.y-B.y)==0;
}
bool InterSection(Point a1,Point a2,Point b1,Point b2)
{
double c1=Cross(a2-a1,b1-a1);
double c2=Cross(a2-a1,b2-a1);
double c3=Cross(b2-b1,a1-b1);
double c4=Cross(b2-b1,a2-b1);
return dcmp(c1)*dcmp(c2)<0&&dcmp(c3)*dcmp(c4)<0;
}
bool InLine(Point P,Point A,Point B)
{
Vector v1=A-P;
Vector v2=B-P;
return dcmp(Cross(v1,v2))==0&&dcmp(Dot(v1,v2))<0;
}
Point Read()
{
double x,y;
scanf("%lf %lf",&x,&y);
return Point(x,y);
}
int N,e,v;
Point a[maxn];
Point V[maxn*maxn];
int kase=0;
int main()
{
while(scanf("%d",&N)==1&&N)
{
for(int i=0;i<N;i++)
{
a[i]=Read();
V[i]=a[i];
}
N--;
e=v=N;
for(int i=0;i<N;i++)
for(int j=0;j<i;j++)
if(InterSection(a[i],a[i+1],a[j],a[j+1]))
V[v++]=GetInterSection(a[i],a[i+1]-a[i],a[j],a[j+1]-a[j]);
sort(V,V+v);
v=unique(V,V+v)-V;
for(int i=0;i<v;i++)
for(int j=0;j<N;j++)
if(InLine(V[i],a[j],a[j+1]))
e++;
printf("Case %d: There are %d pieces.\n",++kase,e-v+2);
}
return 0;
}