poj 2284 That Nice Euler Circuit 计算几何

来源:互联网 发布:java哪个老师出名 编辑:程序博客网 时间:2024/06/05 19:17

主要内容是计算几何,利用了一个图论中的结论平面的区域个数 r=m-n+2,m为边数、n为点数

心血来潮,决定不用别人的模板,手写了模板

1:判断线段相交

2:判断点在线段上

都是些最基本的,不过这些以后就算我自己的啦,用别人的总感觉怪怪的

View Code
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 100000;
const double eps = 1e-8;
const double pi = acos(-1.0);
#define sgn(x) (fabs(x)<eps?0:(x>0?1:-1))
struct Point {
double x, y;
Point(double a=0,double b=0){x=a;y=b;}
Point operator - (const Point& t) const {
Point tmp;
tmp.x = x - t.x;
tmp.y = y - t.y;
return tmp;
}
bool operator < (const Point &p) const {
return sgn(x-p.x)<0 || sgn(x-p.x)==0 && sgn(y-p.y)<0;
}
bool operator == (const Point& t) const {
return sgn(x-t.x)==0 && sgn(y-t.y)==0;
}
}GP;
struct Line {
double a, b, c;
};
struct Seg{
Point s,e;
Seg(Point a,Point b){s=a;e=b;}
};
inline double Cross(Point a, Point b, Point c) {
return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
};
Line Turn(Point s, Point e) {
Line ln;
ln.a =s.y - e.y ;
ln.b =e.x - s.x;
ln.c =s.x*e.y - e.x*s.y;
return ln;
}
bool dotOnSeg(Point p, Point s, Point e) {
if ( p == s || p == e )
return true;
return sgn(Cross(s,e,p))==0 &&
sgn((p.x-s.x)*(p.x-e.x))<=0 && sgn((p.y-s.y)*(p.y-e.y))<=0;//sgn可能等于0,比如线段垂直坐标轴
}
bool Seg_Inst(Seg s1, Seg s2, Point &p) {//判断线段相交,共线时需要特判,先判直线相交,再判点在直线上
Line l1=Turn(s1.s,s1.e),l2=Turn(s2.s,s2.e);
double d = l1.a*l2.b - l2.a*l1.b;
if ( sgn(d) ==0 ) return false;
p.x = (-l1.c*l2.b + l2.c*l1.b) / d;
p.y = (-l1.a*l2.c + l2.a*l1.c) / d;
return dotOnSeg(p,s1.s,s1.e) && dotOnSeg(p,s2.s,s2.e);
}
bool check(Seg s1, Seg s2, Point& pp) {//共线,特判
if ( s1.s==s2.s || s1.s==s2.e ) { pp = s1.s; return true;}
if ( s1.e==s2.s || s1.e==s2.e) {pp = s1.e;return true;}
return false;
}
Point p[maxn],inst[maxn],tp[maxn];
int main(){
int i,j,ca=1,n;
while(scanf("%d",&n),n){
int tot=0,m=0;
for(i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
for(i=0;i<n-1;i++){
Seg s1(p[i],p[(i+1)]);
int cnt=0;
for(j=0;j<n-1;j++){
Seg s2(p[j],p[(j+1)]);
Point t;
if(Seg_Inst(s1,s2,t)){
inst[tot++]=t;
tp[cnt++]=t;
}//可能会有三点共线,上面的线段相交检测不出来
else if(check(s1,s2,t)) {
inst[tot++]=t;//共线的边数多算了,所以点也要加进来,多加几条边就多加几个点,相抵消
tp[cnt++]=t;
}
}
sort(tp,tp+cnt);
m+=unique(tp,tp+cnt)-tp-1;//一条线段上的点数减1等于这条线段上边数
}
sort(inst,inst+tot);
tot=unique(inst,inst+tot)-inst;
printf("Case %d: There are %d pieces.\n",ca++,m+2-tot);
}
return 0;
}