交了12个WA 3个PE。
poj没有case 和原题干里是一致的。
zoj加了case case之间要求有空行(这点在题目描述里,output里没说)。
而且最最坑爹的就是Number of doors = 2数字后面是没有空格的亲们!!!
黑书上的题,以前一直不屑于去做,如今一做感觉真是不一样,毕竟各种解题报告说的解法不是特别特别清晰
解法就是用财富点和正方形边上被割出来的每一条边的中点连成线段,求与所有线段交点的交点数中最小的那一个加一。
就是大黑点和红点连线,求与所有线段的交点中最小的个数+1.
我就不详细证了,所有交点的位置可以定为当前情况下门的位置,而门的位置不影响最终结果。
当然,如果门在两条原线段的交点处是不符合题意的,那么就微小得移动逃出的线段,使得这三条线段不交于一点。
这道题不用考虑不规范相交的情况,因为没有哪条线段的端点在另外一条线段上。
代码:
#include<stdio.h> #include<math.h> #include<algorithm> #define eps 1e-8 using namespace std; struct point{ double x,y; }u,v,pt[110]; struct line{ point a,b; }l[50]; double dis(point a){ return a.x*a.x+a.y*a.y; } int cp(point a,point b,point c){ double t=(c.x-a.x)*(b.y-a.y)-(c.y-a.y)*(b.x-a.x); if(t<-eps)return -1; if(t>eps)return 1; return 0; } int cmp(point a,point b){ if(cp(pt[0],a,b)==0)return dis(a)<dis(b); return cp(pt[0],a,b)<0; } bool on(point a,point b,point c){ return a.x<=max(b.x,c.x)&&a.y<=max(b.y,c.y)&& a.x>=min(b.x,c.x)&&a.y>=min(b.y,c.y); } bool l2l(point a,point b,point c,point d){ int d1=cp(a,b,c); int d2=cp(a,b,d); int d3=cp(c,d,a); int d4=cp(c,d,b); if(d1*d2<0&&d3*d4<0)return 1; return 0; } int n,mint; int jiao(point a,point b){ int i,cnt; for(i=0,cnt=0;i<n&&cnt<mint;i++) if(l2l(a,b,l[i].a,l[i].b)) cnt++; return cnt+1; } int main(){ int i,j,t,cs,top; scanf("%d",&cs); while(cs--){ scanf("%d",&n); for(i=0,top=4;i<n;i++){ scanf("%lf%lf%lf%lf",&l[i].a.x,&l[i].a.y,&l[i].b.x,&l[i].b.y); pt[top++]=l[i].a; pt[top++]=l[i].b; } scanf("%lf%lf",&v.x,&v.y); pt[0].x=0;pt[0].y=0; pt[1].x=100;pt[1].y=0; pt[2].x=0;pt[2].y=100; pt[3].x=100;pt[3].y=100; sort(pt+1,pt+top,cmp); pt[top]=pt[0]; mint=10000; for(i=1;i<=top;i++){ if(fabs(pt[i].x-pt[i-1].x)<eps&&fabs(pt[i].y-pt[i-1].y)<eps) continue; u.x=(pt[i].x+pt[i-1].x)/2; u.y=(pt[i].y+pt[i-1].y)/2; t=jiao(u,v); mint=mint<t?mint:t; } printf("Number of doors = %d\n",mint); if(cs)puts(""); } return 0; }