向量的叉积 POJ 2318 TOYS

题目大意:给定一个盒子的左上角和右下角坐标,然后给n条线,可以将盒子分成n+1个部分,再给m个点,问每个区域内有多少各点

这个题用到关键的一步就是向量的叉积,假设一个点m在 由abcd围成的四边形区域内,那么向量ab, bc, cd, da和点的关系就是,点都在他们的同一侧,我是按照逆时针来算的,所以只需要判断叉积是否小于0就行了。还有一个问题就是这个题要求时间是2s,所以直接找,不用二分也能过,不过超过1s了,最好还是二分来做,二分时间170ms,二分的时候要把最左边的一条边和最右边的一条边都要加到数组中去

代码一(直接找区域)

#include<iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int N = 15500;
struct point{
    int x, y;
};
int n, m, ans[5500];
point upper_left, lower_left, upper_right, lower_right, p[N];
double direction(point a, point b, point c)//判断方向
{
    point t1, t2;
    t1.x = c.x - a.x; t1.y = c.y - a.y;
    t2.x = b.x - a.x; t2.y = b.y - a.y;
    return (t1.x * t2.y * 1.0 - t1.y * t2.x * 1.0);
}
int main()
{
    while (~scanf("%d", &n) && n)
    {
        memset(ans, 0, sizeof(ans));
        int a, b;
        scanf("%d %d %d %d %d", &m, &upper_left.x, &upper_left.y, &lower_right.x, &lower_right.y);
        lower_left.x = upper_left.x; lower_left.y = lower_right.y;
        upper_right.x = lower_right.x; upper_right.y = upper_left.y;
        for (int i = 0; i < 2 * n; i++)
        {
            scanf("%d %d", &a, &b);
            p[i].x = a; p[i].y = upper_left.y;
            p[++i].x = b; p[i].y = lower_right.y;

        }
        point tmp;
        double d1, d2, d3, d4;
        for (int i = 0; i < m; i++)
        {
            scanf("%d %d", &tmp.x, &tmp.y);
            //判断是否在第一个区域内
            d1 = direction(upper_left, lower_left, tmp);
            d2 = direction(lower_left, p[1], tmp);
            d3 = direction(p[1], p[0], tmp);
            d4 = direction(p[0], upper_left, tmp);
            if (d1 <= 0 && d2 <= 0 && d3 <= 0 && d4 <= 0)
            {
                ans[0]++;
                continue;
            }
            bool flag = false;
            for (int j = 0; j < 2 * n - 2; j += 2)
            {
                d1 = direction(p[j], p[j + 1], tmp);
                d2 = direction(p[j + 1], p[j + 3], tmp);
                d3 = direction(p[j + 3], p[j + 2], tmp);
                d4 = direction(p[j + 2], p[j], tmp);
                if (d1 <= 0 && d2 <= 0 && d3 <= 0 && d4 <= 0)
                {
                    ans[j / 2 + 1]++;
                    flag = true;
                    break;
                }
            }
            if (flag)
                continue;
            //d1 = direction(p[2 * n - 2], p[2 * n - 1], tmp);
            //d2 = direction(p[2 * n - 1], lower_right, tmp);
            //d3 = direction(lower_right, upper_right, tmp);
            //d4 = direction(upper_right, p[n * 2 - 2], tmp);
            //if (d1 <= 0 && d2 <= 0 && d3 <= 0 && d4 <= 0)
            ans[n]++;
        }
        for (int i = 0; i <= n; i++)
            printf("%d: %d\n", i, ans[i]);
        puts("");
    }

    return 0;
}

代码二(二分法)

#include<iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int N = 15500;
struct point{
    int x, y;
};
int n, m, ans[5500];
point upper_left, lower_left, upper_right, lower_right, p[N];//各个角
double direction(point a, point b, point c)//判断方向,判断点c在向量ab的哪一侧,如果返回是负值则在逆时针那侧
{
    point t1, t2;
    t1.x = c.x - a.x; t1.y = c.y - a.y;
    t2.x = b.x - a.x; t2.y = b.y - a.y;
    return (t1.x * t2.y * 1.0 - t1.y * t2.x * 1.0);
}
void dichotomization(point tmp)//二分法判断在那块区间内
{
    int left, right, mid;
    left = 0; right = n + 1; mid = (left + right) >> 1;
    while (left < right)
    {
        if (left + 1 == right)
        {
            ans[left]++;
            break;
        }
        double d = direction(p[mid * 2], p[mid * 2 + 1], tmp);
        if (d < 0)
            left = mid;
        else
            right = mid;
        mid = (left + right) >> 1;
    }
}
int main()
{
    while (~scanf("%d", &n) && n)
    {
        memset(ans, 0, sizeof(ans));
        int a, b;
        scanf("%d %d %d %d %d", &m, &upper_left.x, &upper_left.y, &lower_right.x, &lower_right.y);
        lower_left.x = upper_left.x; lower_left.y = lower_right.y;
        upper_right.x = lower_right.x; upper_right.y = upper_left.y;
        p[0] = upper_left;//将边角点加入p数组,为了二分 好计算
        p[1] = lower_left;
        for (int i = 2; i < 2 * n + 2; i++)
        {
            scanf("%d %d", &a, &b);
            p[i].x = a; p[i].y = upper_left.y;
            p[++i].x = b; p[i].y = lower_right.y;

        }
        p[2 * n + 2] = upper_right;
        p[2 * n + 3] = lower_right;
        point tmp;
        for (int i = 0; i < m; i++)
        {
            scanf("%d %d", &tmp.x, &tmp.y);
            dichotomization(tmp);

        }
        for (int i = 0; i <= n; i++)
            printf("%d: %d\n", i, ans[i]);
        puts("");
    }

    return 0;
}

时间: 2024-11-08 21:56:12

向量的叉积 POJ 2318 TOYS的相关文章

poj 2318 TOYS &amp; poj 2398 Toy Storage (叉积)

链接:poj 2318 题意:有一个矩形盒子,盒子里有一些木块线段,并且这些线段坐标是按照顺序给出的, 有n条线段,把盒子分层了n+1个区域,然后有m个玩具,这m个玩具的坐标是已知的,问最后每个区域有多少个玩具 分析:从左往右,直到判断玩具是否在线段的逆时针方向为止,这个就需要用到叉积,当然可以用二分查找优化. 叉积:已知向量a(x1,y1),向量b(x2,y2),axb=x1*y2-x2*y1, 若axb>0,a在b的逆时针方向,若axb<0,则a在b的顺时针方向 注:每组数据后要多空一行

POJ 2318 TOYS(叉积+二分or暴力)

题目链接:POJ 2318 TOYS [写在前面]前几天跟队友分了方向,学渣开始进行计算几何的专题了,真是脑壳有点痛啊.但是我想做多了就没这么坑爹了 [题意]大体意思就是给你一个矩形,有被若干直线分成N个格子,给出M个点的坐标,问你每个点位于哪个格子中. [思路]其实就是点在凸四边形内的判断,然后就可以利用叉积的性质,当然可以用暴力枚举也可以过,但是时间复杂度有点高,最好是用二分求解.(一直觉得二分真是牛逼啊) 下面贴AC代码,用二分219MS就过了: 1 /* 2 ** POJ 2318 TO

POJ 2318 TOYS 叉积的应用

A - TOYS Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2318 Appoint description:  lijunle  (2011-07-18)System Crawler  (2016-05-08) Description Calculate the number of toys that land in each b

POJ 2318 TOYS 叉积

题意: 给出一个矩形范围,给出n条线段,这n条线段一定与矩形上下边界相交且互不相交,将矩形分成n+1个划分.给出m个玩具的坐标.求每个划分放的玩具数,玩具保证不会在线段和左右边界上. 分析: 判断点是否在两条直线中间,利用叉积,如果在两条直线间,必定会有两个叉积一个小于0,一个大于0(不能把相乘小于0作为判断条件) #include <iostream> #include <cstdio> #include <cstring> using namespace std;

POJ 2318 TOYS 利用叉积判断点在线段的那一侧

题意:给定n(<=5000)条线段,把一个矩阵分成了n+1分了,有m个玩具,放在为位置是(x,y).现在要问第几个位置上有多少个玩具. 思路:叉积,线段p1p2,记玩具为p0,那么如果(p1p2 ^ p1p0) (记得不能搞反顺序,不同的),如果他们的叉积是小于0,那么就是在线段的左边,否则右边.所以,可以用二分找,如果在mid的左边,end=mid-1 否则begin=mid+1.结束的begin,就是第一条在点右边的线段 #include <cstdio> #include <

POJ 2318 TOYS 叉积应用

点击打开链接 TOYS Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 11078   Accepted: 5312 Description Calculate the number of toys that land in each bin of a partitioned toy box. Mom and dad have a problem - their child John never puts his toys

POJ 2318 TOYS【叉积+二分】

今天开始学习计算几何,百度了两篇文章,与君共勉! 计算几何入门题推荐 计算几何基础知识 题意:有一个盒子,被n块木板分成n+1个区域,每个木板从左到右出现,并且不交叉. 有m个玩具(可以看成点)放在这个盒子里,问每个区域分别有多少个玩具. 思路:首先,用叉积判断玩具是否在木板的左边,再用二分找到符合的最右边的木板,该木板答案加一. #include<stdio.h> #include<string.h> struct point{ int x,y; point(){} point(

POJ 2318 TOYS(点与直线的关系 叉积&amp;&amp;二分)

题目链接 题意: 给定一个矩形,n个线段将矩形分成n+1个区间,m个点,问这些点的分布. 题解: 思路就是叉积加二分,利用叉积判断点与直线的距离,二分搜索区间. 代码: 最近整理了STL的一些模板,发现真是好用啊orz,为啥以前没发现呢,可能是比较懒吧-.- #include <stdio.h> #include <string.h> #include <cmath> #include <iostream> #include <queue> #i

poj 2318 TOYS 2012-01-11

http://poj.org/problem?id=2318 ___________________________________________________ 题目大意:一个箱子用木板分成几个区间,给一些玩具的坐标,求各个区间有几个玩具. 对于每一个玩具,因为输入的区间是有序的,所以采用二分木板,判断一个玩具在哪个区间. ___________________________________________________ 1 Program Stone; 2 var i,n,m,x1,x