POJ 2318 TOYS
题意是在一个大矩形里有n条分割线把矩形分割成n+1部分、再给出一些玩具的坐标、要求统计每个部分内有多少个玩具、
具体做法就是二分求解出当前玩具右方的第一条线、这可以用叉积判断、
Code:
var res:array [0..5002] of longint; p:array [0..5002] of record x1,x2,y1,y2:double;end; xx,yy,ldx,ldy,rux,ruy:double; n,m,i,l,r,mid:longint; function crossp(x1,y1,x2,y2:double):double; begin crossp:=x1*y2-x2*y1; end; function ok(now:longint):boolean; begin if crossp(p[now].x1-xx,p[now].y1-yy,p[now].x2-xx,p[now].y2-yy)>0 then exit(true) else exit(false); end; begin read(n); while n<>0 do begin readln(m,ldx,ruy,rux,ldy); for i:=1 to n do begin readln(p[i].x2,p[i].x1); p[i].y1:=ldy; p[i].y2:=ruy; end; p[0].x1:=ldx;p[0].x2:=ldx; p[0].y1:=ldy;p[0].y2:=rux; p[n+1].x1:=rux;p[n+1].x2:=rux; p[n+1].y1:=ldy;p[n+1].y2:=ruy; for i:=1 to m do begin readln(xx,yy); l:=1;r:=n+1; while l<r-1 do begin mid:=(l+r) div 2; if ok(mid) then r:=mid else l:=mid; end; while (l>1) and ok(l-1) do dec(l); while not ok(l) do inc(l); inc(res[l-1]); end; for i:=0 to n do writeln(i,': ',res[i]); writeln; fillchar(res,sizeof(res),0); read(n); end; end.
POJ 2398 TOY Storage
本题是上题的姊妹题,区别在于本题要求统计的是包含X个玩具的部分有多少、
P.S 上题的X坐标是有序给出的,而本题要先排序、
Code:
var res,app:array [0..1002] of longint; p:array [0..1002] of record x1,x2,y1,y2:double;end; xx,yy,ldx,ldy,rux,ruy:double; n,m,i,l,r,mid:longint; function crossp(x1,y1,x2,y2:double):double; begin crossp:=x1*y2-x2*y1; end; function ok(now:longint):boolean; begin if crossp(p[now].x1-xx,p[now].y1-yy,p[now].x2-xx,p[now].y2-yy)>0 then exit(true) else exit(false); end; procedure sort(l,r:longint); var i,j:longint; cx:double; begin i:=l;j:=r;cx:=p[random(r-l+1)+l].x1; repeat while p[i].x1<cx do inc(i); while cx<p[j].x1 do dec(j); if i<=j then begin p[1002]:=p[i];p[i]:=p[j];p[j]:=p[1002]; inc(i);dec(j); end; until i>j; if i<r then sort(i,r); if j>l then sort(l,j); end; begin read(n); while n<>0 do begin readln(m,ldx,ruy,rux,ldy); for i:=1 to n do begin readln(p[i].x2,p[i].x1); p[i].y1:=ldy; p[i].y2:=ruy; end; sort(1,n); p[n+1].x1:=rux;p[n+1].x2:=rux; p[n+1].y1:=ldy;p[n+1].y2:=ruy; for i:=1 to m do begin readln(xx,yy); l:=1;r:=n+1; while l<r-1 do begin mid:=(l+r) div 2; if ok(mid) then r:=mid else l:=mid; end; while (l>1) and ok(l-1) do dec(l); while not ok(l) do inc(l); inc(res[l-1]); end; for i:=0 to n do inc(app[res[i]]); writeln('Box'); for i:=1 to n do if app[i]<>0 then writeln(i,': ',app[i]); fillchar(app,sizeof(app),0); fillchar(res,sizeof(res),0); read(n); end; end.
POJ 3304 Segments
本题要求判断是否存在一条直线通过给出的所有直线、
不难想到如果该直线不过任何一条直线的端点,一定可以让它旋转一定角度与某一个端点相碰;
而如果该直线只与某一个相碰,必然可以旋转另一端点与另一个端点相碰、
于是,我们N^2枚举出直线,然后判断是否与每一条线段相交即可、
Code:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #define EPS 1e-8 #define sqr(x) ((x)*(x)) using namespace std; double x[501],y[501]; int n,vv; double dis(double aa,double bb,double cc,double dd){ return sqrt((aa-bb)*(aa-bb)+(cc-dd)*(cc-dd)); } double crossp(double aa,double bb,double cc,double dd){ return aa*dd-bb*cc; } int judge(double x1,double y1,double x2,double y2){ if (dis(x1,x2,y1,y2)<EPS) return 0; for (int j=1;j<=n*2;j++) if (j&1) if (crossp(x[j]-x1,y[j]-y1,x2-x1,y2-y1)*crossp(x2-x1,y2-y1,x[j+1]-x1,y[j+1]-y1)<0) return 0; return 1; } int main(){ scanf("%d",&vv); while (vv--){ scanf("%d",&n); for (int i=1;i<=n*2;i++) scanf("%lf%lf",&x[i],&y[i]); if (n==1){ printf("Yes!\n"); continue; } int succ=0; for (int i=1;i<=n*2 && !succ;i++) for (int j=i+1;j<=n*2 && !succ;j++) if (judge(x[i],y[i],x[j],y[j])) succ++; if (succ) printf("Yes!\n"); else printf("No!\n"); } }
POJ 1269 Pick-up Sticks
本题来自于一个经典的……游戏?
题意主要就是每次放一条线段上去、如果后放的与先放的有交点就覆盖掉先放的、
于是我们可以维护一个随便什么链表、然后维护当前在顶上的线段编号、因为题目保证TOP线段不超过1000条、所以是可以无压力通过的、、
Code:
#include <cstring> #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #define EPS 1e-9 #define sqr(x) ((x)*(x)) #define INF 1e9 #define pb push_back using namespace std; struct segment{ double sx,sy,ex,ey; }ss[100010]; int n,top[1010],tt; double crossp(double x1,double y1,double x2,double y2){ return x1*y2-x2*y1; } 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(){ scanf("%d",&n); while (n){ for (int i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&ss[i].sx,&ss[i].sy,&ss[i].ex,&ss[i].ey); top[tt=1]=1; for (int i=2;i<=n;i++){ for (int j=1;j<=tt;j++) if (cross(ss[top[j]],ss[i])) top[j]=-1; int cur=0; for (int j=1;j<=tt;j++) if (top[j]>0) top[++cur]=top[j]; tt=cur; top[++tt]=i; } printf("Top sticks:"); for (int i=1;i<tt;i++) printf(" %d,",top[i]); printf(" %d.\n",top[tt]); scanf("%d",&n); } return 0; }
POJ 1556 The doors
一看图就知道是什么题了、
把所有出现的点全部建成一张图,然后求解最短路就可以了。
Code:
#include <cstring> #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #define EPS 1e-9 #define sqr(x) ((x)*(x)) #define INF 1e9 #define pb push_back using namespace std; struct segment{ double sx,sy,ex,ey; }ss[100010]; int n,top[1010],tt; double crossp(double x1,double y1,double x2,double y2){ return x1*y2-x2*y1; } 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(){ scanf("%d",&n); while (n){ for (int i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&ss[i].sx,&ss[i].sy,&ss[i].ex,&ss[i].ey); top[tt=1]=1; for (int i=2;i<=n;i++){ for (int j=1;j<=tt;j++) if (cross(ss[top[j]],ss[i])) top[j]=-1; int cur=0; for (int j=1;j<=tt;j++) if (top[j]>0) top[++cur]=top[j]; tt=cur; top[++tt]=i; } printf("Top sticks:"); for (int i=1;i<tt;i++) printf(" %d,",top[i]); printf(" %d.\n",top[tt]); scanf("%d",&n); } return 0; }
POJ 1066 Treasure Hunt
本题大概是说、在(0,0)(100,100)的矩形内有若干线段把矩形分割成若干区域,然后给出一个宝藏的所在地(X,Y)求一条从边界进入到达该点的路径,使得该路径通过的线段最少、
本题与3304有一定相似之处,不难发现只要枚举所有线段的端点到(X,Y)组成的线段与其它线段的交点数就可以了、
Code:
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> using namespace std; struct segment{ double beginx,beginy,endx,endy; }ss[1010]; int n; double nx,ny; segment temp; 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)>0) return 1; return 0; } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&ss[i].beginx,&ss[i].beginy,&ss[i].endx,&ss[i].endy); scanf("%lf%lf",&nx,&ny); temp.endx=nx;temp.endy=ny; int ans=99999999; for (int i=1;i<=n;i++){ int cnt=0; temp.beginx=ss[i].beginx; temp.beginy=ss[i].beginy; for (int j=1;j<=n;j++) if (cross(ss[j],temp)) cnt++; if (cnt<ans) ans=cnt; cnt=0; temp.beginx=ss[i].endx; temp.beginy=ss[i].endy; for (int j=1;j<=n;j++) if (cross(ss[j],temp)) cnt++; if (cnt<ans) ans=cnt; } if (ans==99999999) ans=0; printf("Number of doors = %d\n",ans+1); return 0; }