POJ 2398 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.

1.题目大意:有一个矩形,内部使用若干条线段划分出若干空间,保证这些线段不会相交。给出若干个点,视为一个物体,如果一个区间内含有大于0个物体,那么升序输出含t个物体的区间有多少个

2.这道题和2318那题几乎一模一样,但是需要注意的是坐标是乱序给出的,我们需要先排序。可以证明因为线段不会相交,那么线段的两个x坐标一定不会错乱,那么之间sort即可。接着如何判断在哪个区间呢?对于下面的区间,假设蓝色线段是我们当前判断到的线段,显然该点在当前线段右侧且在他相邻的下一条直线左侧,那么就在这个区间。因为题目数据不大我们直接暴力所有线段就行
在这里插入图片描述
3.但是更推荐的做法是二分,因为该点如果在当前mid左侧,那么右边界左移,否则左边界右移。直到该点不满足了条件,答案就是最后的l(此题最后l还要减一)

int l=1,r=n+1;
while(l<=r){
	int mid=(l+r)/2;
	if(ToLeftTest(Point(p,q),Point(X2[mid],y2),Point(X1[mid],y1))){
		r=mid-1;
	}else l=mid+1;
}

4.对于如何保持t个物体的区间多少个,我直接map+set(STL大法好)。数组也能做,但是没STL直接。特别注意本题和2318还有一处关键不同就是本题没有说点一定在区间内,只说了点不在线段上。吐槽POJ不支持C++11好坑啊…下面是没有写二分的代码

代码:

#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstring>
#include <cstdio>
#include <set>
#include <map>
using namespace std;
#define Point Vector
const int maxn=5010;
const double PI=acos(-1.0);
const double eps=1e-8;

inline int dcmp(double d){   //浮点数和0比较
	if(fabs(d)<eps) return 0;
	return d>0?1:-1;
}


struct Point{
    double x,y;
    Point(double a=0,double b=0):x(a),y(b){}

    Vector operator + (Vector B){
        return Vector(x+B.x,y+B.y);
    }

    Vector operator - (Point B){
        return Vector(x-B.x,y-B.y);
    }

    Vector operator * (double d){  //数乘
        return Vector(x*d,y*d);
    }

    double operator * (Vector B){  //数量积
        return x*B.x+y*B.y;
    }

    Vector operator / (double d){
        return Vector(x/d,y/d);
    }

    double operator ^ (Vector B){  //叉乘
        return x*B.y-y*B.x;
    }

    bool operator < (const Point &b) const {
        if(x==b.x) return y<b.y;
        return x<b.x;
    }

    bool operator == (const Point& b) const {
        if(dcmp(x-b.x)==0 && dcmp(y-b.y)==0)
            return true;
        return false;
    }
};

bool ToLeftTest(Point c, Point b, Point a){ //判断折线bc是不是向ba的逆时针方向(左边)转向
    return ((a-b)^(c-b)) > 0;
}

struct node{
    double X1,X2;
}X[maxn];


int ans[maxn];
set<int> s;
map<int,int> mp;
int n,m;
double x1,yl,x2,y2,x3,y3,x4,y4,p,q;

bool cmp(node &s1,node &s2){
    if(dcmp(s1.X1-s2.X1)==0) return s1.X2<s2.X2;
    return s1.X1<s2.X1;
}

int main()
{
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        scanf("%d",&m);
        mp.clear();
        s.clear();
        memset(ans,0,sizeof ans);
        scanf("%lf%lf%lf%lf",&x1,&yl,&x2,&y2);
        x3=x1,x4=x2;
        X[0].X1=x1,X[0].X2=x3,X[n+1].X1=x4,X[n+1].X2=x2;
        for(int i=1;i<=n;i++){
            scanf("%lf%lf",&X[i].X1,&X[i].X2);
        }
        sort(X,X+n+1,cmp);
        while(m--){
            scanf("%lf%lf",&p,&q);
            if(dcmp(q-yl)>0 || dcmp(y2-q)>0) continue;  //特判
            for(int i=0;i<=n;i++){
                if(!ToLeftTest(Point(p,q),Point(X[i].X2,y2),Point(X[i].X1,yl)) && ToLeftTest(Point(p,q),Point(X[i+1].X2,y2),Point(X[i+1].X1,yl))){
                    ans[i]++;
                    break;
                }
            }
        }
        for(int i=0;i<=n;i++){
            if(!ans[i]) continue;
            s.insert(ans[i]);
            mp[ans[i]]++;
        }
        printf("Box\n");
        for(set<int>::iterator i=s.begin();i!=s.end();i++){
            printf("%d: %d\n",*i,mp[*i]);
        }
    }
    return 0;
}
发布了128 篇原创文章 · 获赞 7 · 访问量 5246

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/104823152
今日推荐