POJ 计算几何专项训练(2) 【1269】&【1410】&【1696】&【3347】&【2826】
POJ 1269 Intersecting Lines
题意很简单、判断两条直线是重合平行还是相交、如果相交输出交点、
Code:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #define EPS 1e-9 #define INF 1e10 using namespace std; int vv; double x1,x2,x3,x4,yy1,y2,y3,y4; bool eq(double x1,double x2){ return abs(x1-x2)<EPS; } double slope(double x1,double y1,double x2,double y2){ if (eq(x1,x2)) return INF; return (y2-y1)/(x2-x1); } int main(){ printf("INTERSECTING LINES OUTPUT\n"); scanf("%d",&vv); while (vv--){ scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&x1,&yy1,&x2,&y2,&x3,&y3,&x4,&y4); double k1=slope(x1,yy1,x2,y2),k2=slope(x3,y3,x4,y4); if (eq(k1,k2)) if ((eq(x1,x2) && eq(x1,x3)) || (eq(yy1-k1*x1,y3-k2*x3))) printf("LINE\n"); else printf("NONE\n"); else{ double b1=yy1-x1*k1,b2=y3-k2*x3; printf("POINT %.2lf %.2lf\n",(b2-b1)/(k1-k2),k1*(b2-b1)/(k1-k2)+b1); } } printf("END OF OUTPUT\n"); return 0; }
POJ 1410 Intersection
判断一条直线和一个矩形是否有公共部分(包含也算)、
Code:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #define EPS 1e-9 #define INF 1e10 using namespace std; struct segment{ double beginx,beginy,endx,endy; }; double crossp(double x1,double y1,double x2,double y2){ return x1*y2-x2*y1; } int cross(segment a,segment b){ if (min(a.beginx,a.endx)>max(b.beginx,b.endx) ||\ min(b.beginx,b.endx)>max(a.beginx,a.endx) ||\ min(a.beginy,a.endy)>max(b.beginy,b.endy) ||\ min(b.beginy,b.endy)>max(a.beginy,a.endy)) return 0; if (crossp(a.beginx-b.beginx,a.beginy-b.beginy,b.endx-b.beginx,b.endy-b.beginy)\ *crossp(b.endx-b.beginx,b.endy-b.beginy,a.endx-b.beginx,a.endy-b.beginy)>=0 &&\ crossp(b.beginx-a.beginx,b.beginy-a.beginy,a.endx-a.beginx,a.endy-a.beginy)\ *crossp(a.endx-a.beginx,a.endy-a.beginy,b.endx-a.beginx,b.endy-a.beginy)>=00) return 1; return 0; } int vv; segment temp,p; double lx,rx,ty,by; int main(){ scanf("%d",&vv); while (vv--){ scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&temp.beginx,&temp.beginy,&temp.endx,&temp.endy,&lx,&ty,&rx,&by); if (lx>rx) swap(lx,rx); if (by>ty) swap(by,ty); if (temp.beginx>=lx && temp.beginx<=rx && temp.beginy>=by && temp.beginy<=ty &&\ temp.endx>=lx && temp.endx<=rx && temp.endy>=by && temp.endy<=ty){ cout <<'T' <<endl; continue; } p.beginx=p.endx=lx;p.beginy=by;p.endy=ty; if (cross(temp,p)){ cout <<'T' <<endl; continue; } p.beginx=p.endx=rx; if (cross(temp,p)){ cout <<'T' <<endl; continue; } p.beginx=lx;p.endx=rx;p.beginy=p.endy=by; if (cross(temp,p)){ cout <<'T' <<endl; continue; } p.beginy=p.endy=ty; if (cross(temp,p)){ cout <<'T' <<endl; continue; } else cout <<'F' <<endl; } return 0; }
POJ 1696 Space Ant
卷包裹的概念题、
Code:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #define INF 1e9 using namespace std; struct point{ int x,y; }; inline int distsquare(point A,point B){return (B.x-A.x)*(B.x-A.x)+(B.y-A.y)*(B.y-A.y);} inline int det(int x1,int y1,int x2,int y2){return x1*y2-x2*y1;} inline int cross(point A,point B,point C,point D){return det(B.x-A.x , B.y-A.y , D.x-C.x , D.y-C.y);} int vv,n; int main(){ scanf("%d",&vv); while(vv--){ scanf("%d",&n); point* node=new point[n+1]; int* conbag=new int[n+1]; bool* vist=new bool[n+1]; int min_y=INF,fi=0; for(int i=1;i<=n;i++){ int num; cin>>num>>node[i].x>>node[i].y; vist[i]=false; if(min_y > node[i].y){ min_y = node[i].y; fi=i; } } conbag[1]=fi;conbag[0]=1;vist[fi]=true; int pc=1; while(1){ int s=conbag[pc]; int k; for(int i=1;i<=n;i++) if(!vist[i]){ k=i; break; } for(int i=1;i<=n;i++) if(i!=k && !vist[i]){ int temp=cross(node[s],node[k],node[s],node[i]); if(temp<0) k=i; else if(temp==0) if(distsquare(node[s],node[k]) > distsquare(node[s],node[i])) k=i; } conbag[++pc]=k;conbag[0]++;vist[k]=true; if(n-conbag[0]==1) break; } printf("%d ",conbag[0]+1); fi=0; for(int i=1;i<=conbag[0];i++){ printf("%d ",conbag[i]); if(!vist[i]) fi=i; } if (fi) cout<<fi<<endl; else cout<<n<<endl; delete node;delete conbag;delete vist; } return 0; }
POJ 3347 Kadj Squares
这个题目很有意思、、
首先,因为无论怎么扩大或者缩小边长,只要是同时对所有图形处理,都不会有问题、于是小数问题被解决了、
其次、对于每个正方形,如果它比前面一个小,显然放在那个的“下面”,否则,情况就比较复杂、于是我为乐简化讨论、对前面所有正方形求一下它能摆的最左位置,然后找出其中的最大值、
最后刷一个高度数组来判断可见、
Code:
#include <cstring> #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #define sign printf("*\n") using namespace std; int h[5001],v[5001],len[5001],p[5001],fr[5001]; int n; int main(){ scanf("%d",&n); while (n){ memset(fr,0,sizeof fr); for (int i=1;i<=n;i++){ scanf("%d",&len[i]); len[i]*=4; } p[1]=0; for (int i=2;i<=n;i++) if (len[i]<len[i-1]) p[i]=p[i-1]+len[i-1]+len[i]; else{ int cur=0; for (int j=1;j<i;j++) if (len[j]>len[i]) cur=max(cur,p[j]+len[j]+len[i]); else cur=max(cur,p[j]+len[j]*3-len[i]); p[i]=cur; } //sign; memset(h,0,sizeof h); for (int i=1;i<=n;i++){ int cur=len[i]; for (int j=0;j<len[i];j++){ if (cur>h[p[i]+j]){ h[p[i]+j]=cur; fr[p[i]+j]=i; } cur++; } if (cur>h[p[i]+len[i]]){ h[p[i]+len[i]]=cur; fr[p[i]+len[i]]=i; } for (int j=len[i]+1;j<=len[i]*2;j++){ cur--; if (cur>h[p[i]+j]){ h[p[i]+j]=cur; fr[p[i]+j]=i; } } } //for (int i=1;i<=n;i++) printf("%d %d\n",i,p[i]); memset(v,0,sizeof v); for (int i=0;i<=5000;i++) v[fr[i]]++; int c=0; for (int i=1;i<=n;i++) if (v[i]){ if (!c) c++;else printf(" "); printf("%d",i); } printf("\n"); scanf("%d",&n); } }
POJ 2826 An Easy Problem?!
太恶心了!、
题意很好理解,然后有以下几种特殊情况:
有水平线;
开口不是朝上的;
两条线段没有交点;
两条线段重合、
以上判断方法都不难、都考虑到就可以了、
(本题实际上是不卡精度的、列方程求解也可过、
Code:
#include <cstring> #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #define EPS 1e-20 #define sqr(x) ((x)*(x)) #define INF 1e9 #define sign printf("*\n") using namespace std; struct segment{ double sx,sy,ex,ey; }; segment s1,s2; int eq(double xx,double yy){ return abs(xx-yy)<EPS; } double dis(double x1,double y1,double x2,double y2){ return sqrt(sqr(x1-x2)+sqr(y1-y2)); } double crossp(double x1,double y1,double x2,double y2){ return x1*y2-x2*y1; } double slope(double x1,double y1,double x2,double y2){ return (eq(x1,x2)?INF:(y2-y1)/(x2-x1)); } int cross(segment a,segment b){ if (max(a.sx,a.ex)<min(b.sx,b.ex) || max(a.sy,a.ey)<min(b.sy,b.ey) \ || min(a.sx,a.ex)>max(b.sx,b.ex) || min(a.sy,a.ey)>max(b.sy,b.ey)) return 0; if (crossp(a.sx-b.sx,a.sy-b.sy,b.ex-b.sx,b.ey-b.sy)*crossp(b.ex-b.sx,b.ey-b.sy,a.ex-b.sx,a.ey-b.sy)>=0 && \ crossp(b.sx-a.sx,b.sy-a.sy,a.ex-a.sx,a.ey-a.sy)*crossp(a.ex-a.sx,a.ey-a.sy,b.ex-a.sx,b.ey-a.sy)>=0) return 1; else return 0; } int main(){ int vv; scanf("%d",&vv); while (vv--){ scanf("%lf%lf%lf%lf",&s1.sx,&s1.sy,&s1.ex,&s1.ey); scanf("%lf%lf%lf%lf",&s2.sx,&s2.sy,&s2.ex,&s2.ey); if (s1.sy>s1.ey){ swap(s1.sx,s1.ex); swap(s1.sy,s1.ey); } if (s2.sy>s2.ey){ swap(s2.sx,s2.ex); swap(s2.sy,s2.ey); } if (!cross(s1,s2)){ printf("0.00\n"); continue; } if (eq(s1.sy,s1.ey) || eq(s2.sy,s2.ey)){ printf("0.00\n"); continue; } double k1=slope(s1.sx,s1.sy,s1.ex,s1.ey); double k2=slope(s2.sx,s2.sy,s2.ex,s2.ey); if (eq(k1,k2)){ printf("0.00\n"); continue; } double b1=s1.sy-k1*s1.sx; double b2=s2.sy-k2*s2.sx; double meetx=(b2-b1)/(k1-k2); double meety=meetx*k1+b1; double h=min(s1.ey,s2.ey); double d=abs((h-b1)/k1-(h-b2)/k2); //printf("%.2lf %.2lf %.2lf %.2lf %.2lf %.2lf %.2lf %.2lf\n",k1,b1,k2,b2,meetx,meety,h,d); if (k1*k2>0) if (abs(k1)>abs(k2)){ if (abs(s1.ex-meetx)>=abs(s2.ex-meetx)){ printf("0.00\n"); continue; } } else if (abs(s1.ex-meetx)<=abs(s2.ex-meetx)){ printf("0.00\n"); continue; } printf("%.2lf\n",0.5*d*(h-meety)+EPS); } }