poj 2398

本文介绍了一道关于计算几何的问题,通过使用点线位置关系及二分查找思想来解决质点在由线段划分的长方形区域内的分布问题。具体探讨了如何通过输入数据计算各分区内质点的数量,并给出了详细的题解代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目概述

有一长方形,左上顶点坐标(x1,y1),右下顶点坐标(x2,y2),被N条上端点为(up,y1),下端点为(low,y2)的线段分成N+1部分,向长方形中扔M个质点,每个点坐标(x,y),求含有不同质点数的分块各有几个

时限

2000ms/6000ms

输入

每组数据第一行6个整数N,M,x1,y1,x2,y2,其后N行,每行2个整数up,low,再其后M行,每行2个整数x,y,输入到N=0结束

限制

1<=N<=5000;1<=M<=5000;所有线段互不相交;所有质点不会落在线段上;所有质点不会落在长方形外面,但落会落在边界上,也视为落在内部;

输出

每组输出第一行为字符串Box,其后若干行,每行格式为
#: @
其中#为质点数,@为含有#个质点的分块数,若分块数@为0,则该行不输出,输出按质点数#升序排列

样例输入

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

样例输出

Box
2: 5
Box
1: 4
2: 1

讨论

计算几何,和poj 2318几乎一样,考察点线位置关系,以及一点二分思想

题解状态

176K,0MS,C++,1323B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f  
#define MAXN 1010
#define memset0(a) memset(a,0,sizeof(a))

struct item//隔板的结构
{
    int up, low;//上下端点横坐标
}items[MAXN];//隔板原始数据
int cnt[MAXN], cnt2[MAXN];//每个分块所含质点数 含相同质点数的分块数
bool pred(item a, item b)//poj不支持c++11的lambda表达式 因而单独拆出
{
    return a.up < b.up;//既然不相交 按上下端点位置判断隔板位置都一样
}
inline int xp(int x1, int y1, int x2, int y2, int x3, int y3)//cross_product 向量积 以点2为公共起点,点1,3为终点 前者所成向量叉乘后者
{
    return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2);
}
void fun(int N, int M, int x1, int y1, int x2, int y2)
{
    for (int p = 1; p <= N; p++)//0下标留给长方形左边界
        scanf("%d%d", &items[p].up, &items[p].low);//input
    items[N + 1].up = items[N + 1].low = x2;//长方形右边界也视为隔板之一
    sort(items + 1, items + N + 1, pred);//与poj 2318相比 隔板是无序出现的 需额外排序
    for (int p = 0; p < M; p++) {//下面是二分过程
        int x, y;
        scanf("%d%d", &x, &y);//input
        int l = 0, r = N + 1, m = (l + r) / 2;
        while (r - l > 1) {
            if (xp(x, y, items[m].low, y2, items[m].up, y1) > 0)
                l = m;
            else
                r = m;
            m = (l + r) / 2;
        }
        cnt[m]++;
    }
    int most = 0;//记录单块所含最多质点数 作为循环边界
    for (int p = 0; p <= N; p++) {
        cnt2[cnt[p]]++;
        most = max(most, cnt[p]);
    }
    printf("Box\n");//output
    for (int p = 1; p <= most; p++)
        if (cnt2[p])
            printf("%d: %d\n", p, cnt2[p]);//output
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int N, M, x1, y1, x2, y2;
    while (~scanf("%d%d%d%d%d%d", &N, &M, &x1, &y1, &x2, &y2) && N) {//input
        fun(N, M, x1, y1, x2, y2);
        memset0(cnt);
        memset0(cnt2);//由于都是采用递增方式赋值 因而都需要清零
    }
}

EOF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值