思路:枚举四边墙的门的中点,与终点连成一条线段,判断与其相交的线段的个数。最小的加一即为答案。
我是傻逼,一个数组越界调了两个小时。
#include<stdio.h> #include<string.h> #include<math.h> #include<iostream> using namespace std; const int N=1000; const double eps=1e-8; int sgn(double x){ if(fabs(x)<eps) return 0; if(x>0) return 1; return -1; } struct point{ double x,y; point(){} point(double x_,double y_){ x=x_,y=y_; } point operator -(const point &b)const{ return point(x-b.x,y-b.y); } double operator *(const point &b)const{ return x*b.x+y*b.y; } double operator ^(const point &b)const{ return x*b.y-y*b.x; } }po[N]; struct line{ point s,e; line(){} line(point s_,point e_){ s=s_,e=e_; } }li[N]; double cal(point p0,point p1,point p2){//叉积 return (p1-p0)^(p2-p0); } int xj(line a,line b){//判断两线段是否相交 point A=a.s,B=a.e,C=b.s,D=b.e; return max(A.x,B.x)>=min(C.x,D.x) && max(C.x,D.x)>=min(A.x,B.x) && max(A.y,B.y)>=min(C.y,D.y) && max(C.y,D.y)>=min(A.y,B.y) && sgn(cal(C,A,B))*sgn(cal(D,A,B))<=0 && sgn(cal(A,C,D))*sgn(cal(B,C,D))<=0; } int p[111][111]; int main(){ int n,i,j,js; double x1,y1,x2,y2; while(~scanf("%d",&n)){ memset(p,0,sizeof(p));js=0; for(i=1;i<=n;i++){ scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); p[(int)x1][(int)y1]=p[(int)x2][(int)y2]=1; li[i]=line(point(x1,y1),point(x2,y2)); } scanf("%lf%lf",&x1,&y1); point P=point(x1,y1); p[0][0]=1; p[0][100]=1; p[100][100]=1; p[100][0]=1; int x0,y0; for(y0=0,i=1;i<=100;i++){ if(p[0][i]){ po[++js]=point(0,(i+y0)/2.0); y0=i; } } for(x0=0,i=1;i<=100;i++){ if(p[i][100]){ po[++js]=point((i+x0)/2.0,100); x0=i; } } for(y0=0,i=1;i<=100;i++){ if(p[100][i]){ po[++js]=point(100,(i+y0)/2.0); y0=i; } } for(x0=0,i=1;i<=100;i++){ if(p[i][0]){ po[++js]=point((i+x0)/2.0,0); x0=i; } } int ans=1000; for(i=1;i<=js;i++){ line L=line(P,po[i]); int cnt=0; for(j=1;j<=n;j++){ if(xj(L,li[j])){ cnt++; } } if(cnt<ans) ans=cnt; } printf("Number of doors = %d ",ans+1); } return 0; }