poj 2318 TOYS 與 poj 2398 Toy Storage(叉積的應用:點線上段的左邊或者右邊)
阿新 • • 發佈:2018-11-05
題目連結:poj 2318
題意:給你一個盒子的俯檢視,從左到右將每個格子劃分為0,1,2...n;給你一些點的座標,讓你輸出每個格子裡點的個數。
題解見程式碼:
///向量P和向量Q ,假如P*Q>0 ,P在Q的順時針方向 ///p*Q<0,P在Q的逆時針方向上, ///點a線上段bc的左邊,則它們的叉積小於0,點a線上段bc的右邊,則它們的叉積大於0, ///https://blog.csdn.net/wangzhen_yu/article/details/44177449 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; struct point{ double x,y; point(double x=0,double y=0):x(x),y(y){ } }; struct line{ point S; point E; }card[5050]; point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);} point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);} point operator * (point a,double p) { return point(a.x*p,a.y*p);} point operator / (point a,double p){ return point(a.x/p,a.y/p);} bool operator < (const point &a,const point &b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); } const double esp=1e-10; int dcmp(double x){ if(fabs(x)<esp) return 0; else return x<0?-1:1; } bool operator ==(const point &a,point &b){ return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } double Cross(point a,point b){ return a.x*b.y-a.y*b.x;} double area2(point a,point b,point c){ return Cross(b-a,c-a);} int sum[5050]; int main() { int n,m; double x1,y1,x2,y2; while(scanf("%d",&n)&&n) { scanf("%d%lf%lf%lf%lf",&m,&x1,&y1,&x2,&y2); card[0].S.x=x1; card[0].S.y=y1; card[0].E.x=x1; card[0].E.y=y2; card[n+1].S.x=x2; card[n+1].S.y=y1; card[n+1].E.x=x2; card[n+1].E.y=y2; double l,r; for(int i=1;i<=n;i++){ scanf("%lf%lf",&l,&r); card[i].S.x=l; card[i].S.y=y1; card[i].E.x=r; card[i].E.y=y2; } memset(sum,0,sizeof(sum)); for(int i=1;i<=m;i++) { point p; scanf("%lf%lf",&p.x,&p.y); for(int j=0;j<=n;j++) { ///判斷點是不是夾在第j條和第j+1條線段之間 if(dcmp((area2(p,card[j].S,card[j].E)))*dcmp((area2(p,card[j+1].S,card[j+1].E)))<0){ sum[j]++; // break; } } } for(int i=0;i<=n;i++) { printf("%d: %d\n",i,sum[i]); } puts(""); } return 0; }
題目連結:http://poj.org/problem?id=2398
題意:跟上一題類似不過這題線段(也就是題目中所說的紙板)不是按照順序給出的,需要進行排次序,然後題目要求的是有多少個空間裡放t個玩具。比如第一組樣例中每個空間裡都是2個玩具,所以輸出2:5.第二組樣例有四個空間裡有1個玩具,有1個空間裡有2個玩具,所以如上輸出。
程式碼如下:
///類似於poj 2318,這裡我們採用二分解決方法去做 ///向量P和向量Q ,假如P*Q>0 ,P在Q的順時針方向 ///p*Q<0,P在Q的逆時針方向上, ///點a線上段bc的左邊,則它們的叉積小於0,點a線上段bc的右邊,則它們的叉積大於0 ///故我們可以二分隔板,只要叉積小於0的隔板 #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int maxn=5050; struct point { int x,y; point(){} point(int _x,int _y){ x=_x;y=_y; } }; point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);} point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);} point operator * (point a,double p) { return point(a.x*p,a.y*p);} point operator / (point a,double p){ return point(a.x/p,a.y/p);} struct line{ point S; point E; line(){} line (point _S,point _E){ S=_S;E=_E; } }card[maxn]; bool operator < (const point &a,const point &b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); } const double esp=1e-5; int dcmp(double x){ if(fabs(x)<esp) return 0; else return x<0?-1:1; } bool operator == (const point &a,const point &b){ return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0; } double Cross(point a,point b) { return a.x*b.y-a.y*b.x;} double area2(point a,point b, point c) {return Cross(b-a,c-a);} bool cmp(line a,line b){ return a.S.x<b.S.x; } int ans[maxn],num[maxn];///ans[i]表示有多少個玩具在第i塊空間,num[i]表示空間內有i個玩具的有多少個空間 int main() { int n,m; double x1,y1,x2,y2; while(scanf("%d",&n)&&n) { scanf("%d%lf%lf%lf%lf",&m,&x1,&y1,&x2,&y2); double Ui,Li; for(int i=0;i<n;i++){ scanf("%lf%lf",&Ui,&Li); card[i]=line(point(Ui,y1),point(Li,y2)); } card[n]=line(point(x2,y1),point(x2,y2)); sort(card,card+n+1,cmp); double x,y; memset(ans,0,sizeof(ans)); point p; while(m--) { scanf("%lf%lf",&x,&y); p=point(x,y); int L=0,R=n; int item; while(L<=R) ///二分 { int mid=(L+R)/2; if(dcmp(area2(p,card[mid].S,card[mid].E))<0){ ///滿足條件,繼續往左縮 item=mid; R=mid-1; } else L=mid+1; } // printf("item=%d\n",item); ans[item]++; } memset(num,0,sizeof(num)); for(int i=0;i<=n;i++) { // printf("ans[%d]=%d\n",i,ans[i]); if(ans[i]) num[ans[i]]++; } printf("Box\n"); for(int i=1;i<=n;i++) if(num[i]) printf("%d: %d\n",i,num[i]); } return 0; }
我的標籤:不拿獎,誓不成人。