POJ1039(管道问题 直线交点)

题目链接: http://poj.org/problem?id=1039

 

 

题意:给出一条曲折的管道,问从入口射的光线最远能达到的距离的x坐标.

 

题意很容易理解,由于直线是任意的,可以想到,只有经过上方与下方折点的光线能达到最右侧,所以需要做的就是枚举经上方与下方折点的每条直线,然后求出它能到达的最右侧x坐标,更新结果,这里需要对其是否能通过管道进行判断,可以把管道的每个转折处看成一条垂直的线段,然后判相交,如果与当前节不相交,刚该直线必与以当前节上下两端点为端点的上下两条边之一相交,根据判断可得其中一...

 

终于知道为什么好多人都不喜欢计算几何问题了,精度啊,这个,一个控制不好,那个结果就是天壤之别啊,而且这种差距是在实例中明显看得到的,你就是不知道如何处理,WA了好多次...好在,花了一整晚,整理了下思路,又重新把代码敲了一遍,AC了,

 

 

8479712 dooder_daodao 1039 Accepted 168K 47MS C++ 1444B 2011-04-13 11:04:46

 

代码如下:

#include<stdio.h> #include<string.h> #include<math.h> #define M 24 const double eps=1e-7; const double left=-10e8; typedef struct{ double x,y; }Point; Point p[M]; //自己推的,分别给出两条直线的两个标 //志点,求出这两条直线的交点横坐标 double Fix(Point pl,Point pr,Point ql,Point qr) { double x; x=(pl.y-ql.y)*(qr.x-ql.x)*(pr.x-pl.x) + ql.x*(qr.y-ql.y)*(pr.x-pl.x) - pl.x*(pr.y-pl.y)*(qr.x-ql.x); x/=(qr.y-ql.y)*(pr.x-pl.x)-(pr.y-pl.y)*(qr.x-ql.x); return x; } int main() { Point pl,pr,ql,qr,tmp; double ans,right; int i,j,k,n; while(scanf("%d",&n),n){ for(i=0;i<n;i++) scanf("%lf%lf",&p[i].x,&p[i].y); ans=left; for(i=0;i<n;i++){ for(j=0;j<n;j++){ if(i==j) continue; ql=p[i]; qr=p[j];qr.y-=1.0; //枚举每条直线,ql'qr 为直线上两点 right=left; for(k=0;k<n;k++){ tmp.x=p[k].x; tmp.y=(tmp.x-ql.x)*(qr.y-ql.y) /(qr.x-ql.x)+ql.y; //如果能通过管道的当前转折点 if(tmp.y>(p[k].y-1.0)&&tmp.y<p[k].y ||fabs(tmp.y-p[k].y+1.0)<eps ||fabs(tmp.y-p[k].y)<eps) right=tmp.x; //不能通过,则必与上或下一条边界相交 //并根据求出的tmp点,得知与哪条边相交 else{ if(k>0){ //线段plpr; pl=p[k-1]; pr=p[k]; if(tmp.y<(p[k].y-1.0)){ pl.y-=1.0;pr.y-=1.0; right=Fix(pl,pr,ql,qr); } else{ right=Fix(pl,pr,ql,qr); } } break; } } //更新能达到的最右侧x坐标 if(right>ans) ans=right; } } //如果能通过整个管道 if(ans>p[n-1].x||fabs(ans-p[n-1].x)<eps) puts("Through all the pipe."); else printf("%.2f/n",ans); } return 0; } 

 

 

 

你可能感兴趣的:(struct,ini)