POJ - 4048 Chinese Repeating Crossbow 暴力列舉+線段香蕉?
阿新 • • 發佈:2019-01-01
題目連結:點選檢視
題意:從一給出的點出發可以向任意方向發出射線,然後現在平面上共有1500條線段,問最多能使射線和幾條線段相交
題解:每個線段都有一個對應的角度範圍,剛開始想的是離散化一下,求一下哪個範圍包括的最多,但是對應的範圍是一個360度的圈,沒法操作,然後注意到了資料只有1500,這樣就可以暴力所有的端點,列舉每一條線段判斷是否相交即可,射線我們可以抽象成線段,先判斷射線的方向,然後把另一端點x設成10000,或-10000 ,y座標相似求一下即可
兩線段相交模板:點選檢視,用過好幾次了,挺好用的,可以儲存一下。
#include<iostream> #include<cstdio> #include<vector> #include<map> #include<algorithm> using namespace std; typedef long long ll; const int N=50010; struct node{ int x1,y1,x2,y2; }aa[1100]; struct node1{ int x,y; }p[2100]; struct Point{ double x,y; }; int n,len; int xx,yy; map<int,map<int,int> > mp; bool judge(int i,int j) { Point a,b,c,d; a.x=xx; a.y=yy; if(p[i].x==xx) { b.x=p[i].x; if(p[i].y>yy) b.y=10000; else b.y=-10000; } else if(p[i].x>xx) { b.x=10000; b.y=(double)(10000.0-xx)/(p[i].x-xx)*(p[i].y-yy)+yy; } else { b.x=-10000; b.y=(double)(xx+10000)/(xx-p[i].x)*(p[i].y-yy)+yy; } c.x=aa[j].x1; c.y=aa[j].y1; d.x=aa[j].x2; d.y=aa[j].y2; if(!(min(a.x,b.x)<=max(c.x,d.x) && min(c.y,d.y)<=max(a.y,b.y)&&min(c.x,d.x)<=max(a.x,b.x) && min(a.y,b.y)<=max(c.y,d.y))) return false; double u,v,w,z; u=(c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y); v=(d.x-a.x)*(b.y-a.y)-(b.x-a.x)*(d.y-a.y); w=(a.x-c.x)*(d.y-c.y)-(d.x-c.x)*(a.y-c.y); z=(b.x-c.x)*(d.y-c.y)-(d.x-c.x)*(b.y-c.y); return (u*v<=0.00000001 && w*z<=0.00000001); } int main() { int T; int x,y; scanf("%d",&T); while(T--) { len=0; mp.clear(); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&aa[i].x1,&aa[i].y1,&aa[i].x2,&aa[i].y2); if(!mp[aa[i].x1][aa[i].y1]) { mp[aa[i].x1][aa[i].y1]=1; p[++len].x=aa[i].x1; p[len].y=aa[i].y1; } if(!mp[aa[i].x2][aa[i].y2]) { mp[aa[i].x2][aa[i].y2]=1; p[++len].x=aa[i].x2; p[len].y=aa[i].y2; } } scanf("%d%d",&xx,&yy); int ans=0; for(int i=1;i<=len;i++) { int cnt=0; for(int j=1;j<=n;j++) if(judge(i,j)) cnt++; ans=max(cnt,ans); } printf("%d\n",ans); } return 0; }