[poj2398]Toy Storage--计算几何,矢量叉积

题目描述

Mom and dad have a problem: their child, Reza, never puts his toys away when he is finished playing with them. They gave Reza a rectangular box to put his toys in. Unfortunately, Reza is rebellious and obeys his parents by simply throwing his toys into the box. All the toys get mixed up, and it is impossible for Reza to find his favorite toys anymore.
Reza’s parents came up with the following idea. They put cardboard partitions into the box. Even if Reza keeps throwing his toys into the box, at least toys that get thrown into different partitions stay separate. The box looks like this from the top:

这里写图片描述

We want for each positive integer t, such that there exists a partition with t toys, determine how many partitions have t, toys.

Input

The input consists of a number of cases. The first line consists of six integers n, m, x1, y1, x2, y2. The number of cardboards to form the partitions is n (0 < n <= 1000) and the number of toys is given in m (0 < m <= 1000). The coordinates of the upper-left corner and the lower-right corner of the box are (x1, y1) and (x2, y2), respectively. The following n lines each consists of two integers Ui Li, indicating that the ends of the ith cardboard is at the coordinates (Ui, y1) and (Li, y2). You may assume that the cardboards do not intersect with each other. The next m lines each consists of two integers Xi Yi specifying where the ith toy has landed in the box. You may assume that no toy will land on a cardboard.

A line consisting of a single 0 terminates the input.

Output

For each box, first provide a header stating “Box” on a line of its own. After that, there will be one line of output per count (t > 0) of toys in a partition. The value t will be followed by a colon and a space, followed the number of partitions containing t toys. Output will be sorted in ascending order of t for each box.

Sample Input

4 10 0 10 100 0
20 20
80 80
60 60
40 40
5 10
15 10
95 10
25 10
65 10
75 10
35 10
45 10
55 10
85 10
5 6 0 10 60 0
4 3
15 30
3 1
6 8
10 10
2 1
2 8
1 5
5 5
40 10
7 9
0

Sample Output

Box
2: 5
Box
1: 4
2: 1

题解:

这道题目的题意就是给你一个盒子,这个盒子被很多个隔板分成很多个格子,然后给出若干个点,要你求出有 i = 1 n 个点的格子各有多少个。

这道题目可以说是矢量叉乘的入门题了吧。。。

首先我们可以很快想到我们可以二分查找找出这个点左边的第一个隔板是哪一个,但是问题是,怎么判断呢?可以用矢量叉乘来判断:

假设我们有两个矢量 p 1 , p 2 ,那么它们两个的叉乘满足:

1.如果 p 1 × p 2 为正数,那么相对于原点 ( 0 , 0 ) 来说, p 1 p 2 的顺时针方向

2.如果 p 1 × p 2 为负数,那么相对于原点 ( 0 , 0 ) 来说, p 1 p 2 的逆时针方向

3.如果 p 1 × p 2 等于0,那么 p 1 p 2 共线,方向相同或者相反。

我们知道上面这个就可以判断一个点是否在一条线段的左边了(右边同理):假设一条线段的下面这个点为 a 1 ,上面这个点为 a 2 ,我们要判断的这个点为 p ,那么我们就可以先求出从 a 1 a 2 的矢量 p 1 ,再求出从 a 1 p 的矢量 p 2 ,那么通过我们上面讲的结论,如果 p 2 × p 1 为正数(要记住叉积中顺序很重要,不然求出的值就是反的),那么 p 就在线段 a 1 a 2 的右边,为负数就在左边,为0就在线段上。

那么刚开始的操作就是把隔板排个序,然后就可以二分了,记得输出的格式。。。

这道题就讲完了。。下面上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 1010
using namespace std;
struct P{
    int x,y;
}a[maxn],b[maxn];
int n,m;
struct X{
    int u,d;
}l[maxn];
bool cmp(X x,X y)
{
    return x.u<y.u;
}
int cnt[maxn],ans[maxn];
int operator * (P a,P b)
{
    return a.x*b.y-b.x*a.y;
}
bool check(int p,P o)//判断点和线段关系
{
    P p1,p2;
    p1.x=a[p].x-b[p].x;p1.y=a[p].y-b[p].y;
    p2.x=o.x-b[p].x;p2.y=o.y-b[p].y;
    int tmp=p2*p1;
    if(tmp>=0)  return true;
    return false;
}
int main()
{
    while(~scanf("%d",&n)&&n) 
    {
        memset(cnt,0,sizeof(cnt));
        memset(ans,0,sizeof(ans));
        scanf("%d",&m);
        scanf("%d%d%d%d",&a[0].x,&a[0].y,&b[n+1].x,&b[n+1].y);
        b[0].x=a[0].x;b[0].y=b[n+1].y;
        a[n+1].x=b[n+1].x;a[n+1].y=a[0].y;//将左右隔板看成线段
        for(int i=1;i<=n;i++)  scanf("%d%d",&l[i].u,&l[i].d);
        sort(l+1,l+n+1,cmp);
        for(int i=1;i<=n;i++){
            a[i].x=l[i].u;a[i].y=a[0].y;
            b[i].x=l[i].d;b[i].y=b[0].y;
        }
        for(int i=1;i<=m;i++)
        {
            P p;
            scanf("%d%d",&p.x,&p.y);
            if(p.x<a[0].x||p.x>a[n+1].x||p.y<b[0].y||p.y>a[0].y)  continue;
            int l=0,r=n;
            int res;
            while(l<=r)//二分
            {
                int mid=(l+r)/2;
                if(check(mid,p)==true)
                {
                    res=mid;
                    l=mid+1;
                }
                else r=mid-1;
            }
            ans[res+1]++;
        }
        for(int i=1;i<=n+1;i++)  cnt[ans[i]]++;
        puts("Box");
        for(int i=1;i<=m;i++)
        {
            if(cnt[i]){
                printf("%d: %d\n",i,cnt[i]);
            }
        }
    }
    return 0;
}

谢谢大家!!!

猜你喜欢

转载自blog.csdn.net/dark_dawn/article/details/81395385
今日推荐