poj(2318)——TOYS(叉积的简单应用)

第一道计算几何题。。

题意:

在一个长方形盒子中被线段划分成了几段区域,然后每段区域中都有一些物品,让你判断在每个区域中分别有几个物品。

叉积的简单应用:

这就要用到向量叉积。叉积的一个非常重要的性质是通过它的符号判断两向量相互之间的顺逆时针关系:设向量P=(x1,y1),Q=(x2,y2)

如果P*Q>0则P在Q的顺时针方向;

如果P*Q=0则P与Q共线,可能同向,与可能反向;

如果P*Q<0则P在Q的逆时针方向。

  (请注意这里是叉乘)


这里要注意一点就是我们在做叉积的时候,要先选择好是按照下面还是按照上面部分作为起始点。也就是在算向量时的起始点。要不然的话会使叉积的顺时针或是逆时针不同,这样就会使答案不一样了。


#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
#include<time.h>
using namespace std;
typedef __int64 ll;
typedef unsigned __int64 ULL;
#define pi acos(-1.0)
#define Ex exp(1.0)
#define maxn 5050*2
int vis[5050];
struct node{
    int x,y,idx;
}a[maxn],b[maxn];
struct Point{
    int x,y;
    Point(int x=0,int y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator - (Point A,Point B){
    return Vector(A.x-B.x,A.y-B.y);
}
Vector operator * (Point A,double p){
    return Vector(A.x*p,A.y*p);
}
int Cross(Vector A,Vector B){
    return A.x*B.y-A.y*B.x;
}
int main(){
    int n,m,x1,y1,x2,y2;
    while(~scanf("%d",&n)){
        if(n==0) break;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
        for(int i=1;i<=n;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            a[i].x=u,a[i].y=y1,a[i+5000].x=v,a[i+5000].y=y2;
            //我这里是选择了y1作为下面,也就是向量的起始点,要不然会导致错误
            //因为如果不统一的话会导致一会儿以上面的点算为起始点,一会儿以下面的点作为起始点
            //从而导致叉积的不同,从而导致无法统一方向。
            swap(a[i].x,a[i+5000].x);
            swap(a[i].y,a[i+5000].y);
        }
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            b[i].x=u,b[i].y=v;
        }
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(vis[j]) continue;
                Vector A,B,C;
                A.x=a[i].x;
                A.y=a[i].y;
                B.x=a[i+5000].x;
                B.y=a[i+5000].y;
                C.x=b[j].x;
                C.y=b[j].y;
                C=C-A;
                A=B-A;
                if(Cross(C,A)>0){
                    if(i==n){
                        vis[j]=1;
                        a[i].idx++;
                        continue;
                    }
                    Vector D,E,F;
                    D.x=a[i+1].x;
                    D.y=a[i+1].y;
                    E.x=a[(i+1)+5000].x;
                    E.y=a[(i+1)+5000].y;
                    F.x=b[j].x;
                    F.y=b[j].y;
                    F=F-D;
                    D=E-D;
                    if(Cross(F,D)<0){
                        vis[j]=1;
                        a[i].idx++;
                    }
                }
                else if(Cross(C,A)<=0){
                    if(i==1){
                        vis[j]=1;
                        a[i-1].idx++;
                        continue;
                    }
                    Vector D,E,F;
                    D.x=a[i-1].x;
                    D.y=a[i-1].y;
                    E.x=a[(i-1)+5000].x;
                    E.x=a[(i-1)+5000].y;
                    F.x=b[j].x;
                    F.y=b[j].y;
                    F=F-D;
                    D=E-D;
                    if(Cross(F,D)>0){
                        vis[j]=1;
                        a[i-1].idx++;
                    }
                }
            }
        }
        for(int i=0;i<=n;i++){
            printf("%d: %d\n",i,a[i].idx);
        }
        printf("\n");
    }
    #ifndef ONLINE_JUDGE
    system("pause");
    #endif
    return 0;
}
/*
5 6 0 10 60 0
3 1
4 3
6 8
10 10
15 30
1 5
2 1
2 8
5 5
40 10
7 9
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值