向量的叉积 POJ 2318 TOYS & POJ 2398 Toy Storage
POJ 2318:
题目大意:给定一个盒子的左上角和右下角坐标,然后给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 = ;
struct point{
int x, y;
};
int n, m, ans[];
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, , 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 = ; i < * 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 = ; i < m; i++)
{
scanf("%d %d", &tmp.x, &tmp.y);
//判断是否在第一个区域内
d1 = direction(upper_left, lower_left, tmp);
d2 = direction(lower_left, p[], tmp);
d3 = direction(p[], p[], tmp);
d4 = direction(p[], upper_left, tmp);
if (d1 <= && d2 <= && d3 <= && d4 <= )
{
ans[]++;
continue;
}
bool flag = false;
for (int j = ; j < * n - ; j += )
{
d1 = direction(p[j], p[j + ], tmp);
d2 = direction(p[j + ], p[j + ], tmp);
d3 = direction(p[j + ], p[j + ], tmp);
d4 = direction(p[j + ], p[j], tmp);
if (d1 <= && d2 <= && d3 <= && d4 <= )
{
ans[j / + ]++;
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 = ; i <= n; i++)
printf("%d: %d\n", i, ans[i]);
puts("");
} return ;
}
代码二(二分法)
#include<iostream>
#include <cstdio>
#include <string.h>
using namespace std;
const int N = ;
struct point{
int x, y;
};
int n, m, ans[];
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 = ; right = n + ; mid = (left + right) >> ;
while (left < right)
{
if (left + == right)
{
ans[left]++;
break;
}
double d = direction(p[mid * ], p[mid * + ], tmp);
if (d < )
left = mid;
else
right = mid;
mid = (left + right) >> ;
}
}
int main()
{
while (~scanf("%d", &n) && n)
{
memset(ans, , 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[] = upper_left;//将边角点加入p数组,为了二分 好计算
p[] = lower_left;
for (int i = ; i < * 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; }
p[ * n + ] = upper_right;
p[ * n + ] = lower_right;
point tmp;
for (int i = ; i < m; i++)
{
scanf("%d %d", &tmp.x, &tmp.y);
dichotomization(tmp); }
for (int i = ; i <= n; i++)
printf("%d: %d\n", i, ans[i]);
puts("");
} return ;
}
POJ 2398:
这道题和上一题类似,包括主要过程也一样,但是有个条件不一样,上一个题它给的n条线时有序的,就是从左往右的,但是这个没有顺序,是随便给的,所以要把它排一下序,最后让求的,假设是一个区域内有t个点,的这样的区域有多少个,按照升序打印出来:
代码如下:
#include<iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = ;
struct point{
int x, y;
};
struct Edge{
point Start, End;
};
Edge edge[N];
int n, m, ans[N], res[N];
point upper_left, lower_left, upper_right, lower_right, p[N];//各个角
bool cmp(Edge e1, Edge e2)
{
if (e1.Start.x != e2.Start.x)
return e1.Start.x < e2.Start.x;
return e1.End.x < e2.End.x;
}
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_edge(point tmp)
{
int left, right, mid;
left = ; right = n + ; mid = (left + right) >> ;
while (left < right)
{
if (left + == right)
{
ans[left]++;
break;
}
double d = direction(edge[mid].Start, edge[mid].End, tmp);
if (d < )
left = mid;
else
right = mid;
mid = (left + right) >> ;
}
}
int main()
{
while (~scanf("%d", &n) && n)
{
memset(ans, , sizeof(ans));
point t1, t2;
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;
edge[].Start = upper_left;
edge[].End = lower_left;
for (int i = ; i <= n; i++)
{
scanf("%d %d", &t1.x, &t2.x);
t1.y = upper_left.y;
t2.y = lower_right.y;
edge[i].Start = t1;
edge[i].End = t2;
}
edge[n + ].Start = upper_right;
edge[n + ].End = lower_right;
point tmp;
sort(edge, edge + n + , cmp);
for (int i = ; i < m; i++)
{
scanf("%d %d", &tmp.x, &tmp.y);
dichotomization_edge(tmp); }
memset(res, , sizeof(res));
for (int i = ; i <= n; i++)
if (ans[i] != )
res[ans[i]]++;
printf("Box\n");
for (int i = ; i < ; i++)
if (res[i] != )
printf("%d: %d\n", i, res[i]);
} return ;
}
向量的叉积 POJ 2318 TOYS & POJ 2398 Toy Storage的更多相关文章
- POJ 2318 TOYS && POJ 2398 Toy Storage(几何)
2318 TOYS 2398 Toy Storage 题意 : 给你n块板的坐标,m个玩具的具体坐标,2318中板是有序的,而2398无序需要自己排序,2318要求输出的是每个区间内的玩具数,而231 ...
- 简单几何(点与线段的位置) POJ 2318 TOYS && POJ 2398 Toy Storage
题目传送门 题意:POJ 2318 有一个长方形,用线段划分若干区域,给若干个点,问每个区域点的分布情况 分析:点和线段的位置判断可以用叉积判断.给的线段是排好序的,但是点是无序的,所以可以用二分优化 ...
- POJ 2318 TOYS/POJ 2398 Toy Storage
计算几何终于开坑了... 叉积+二分. #include<iostream> #include<cstdio> #include<cstring> #include ...
- POJ 2318 TOYS(叉积+二分)
题目传送门:POJ 2318 TOYS Description Calculate the number of toys that land in each bin of a partitioned ...
- poj 2398 Toy Storage(计算几何)
题目传送门:poj 2398 Toy Storage 题目大意:一个长方形的箱子,里面有一些隔板,每一个隔板都可以纵切这个箱子.隔板将这个箱子分成了一些隔间.向其中扔一些玩具,每个玩具有一个坐标,求有 ...
- poj 2318 TOYS & poj 2398 Toy Storage (叉积)
链接:poj 2318 题意:有一个矩形盒子,盒子里有一些木块线段.而且这些线段坐标是依照顺序给出的. 有n条线段,把盒子分层了n+1个区域,然后有m个玩具.这m个玩具的坐标是已知的,问最后每一个区域 ...
- poj 2318 TOYS (二分+叉积)
http://poj.org/problem?id=2318 TOYS Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 101 ...
- POJ 2398 Toy Storage(计算几何,叉积判断点和线段的关系)
Toy Storage Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 3146 Accepted: 1798 Descr ...
- 2018.07.03 POJ 2318 TOYS(二分+简单计算几何)
TOYS Time Limit: 2000MS Memory Limit: 65536K Description Calculate the number of toys that land in e ...
随机推荐
- Linux 查看文件内容的命令
转载自:新浪博客 (观看档案内容 : cat, tac, more, less, head, tail, nl, 刚刚我们提到的都只是在于显示档案的外观,或者是移动与复制一个档案或目录而已,那么如果我 ...
- 利用xampp进行https操作
环境:win7 32位 安装xampp: 一般情况Apache的端口号可能会冲突,建议修改.修改方法如下: 1.点击Config
- javascript禁止输入数字
function onkeypressIsNumber(){ var mainForm = document.mainForm;//mainForm是form表单的ID for(var i=0; i& ...
- Oauth支持的5类 grant_type 及说明
authorization_code 授权码模式(即先登录获取code,再获取token) password 密码模式(将用户名,密码传过去,直接获取token) client_credentials ...
- Thinkphp 表单验证
在服务器端通过tp框架实现表单验证 用户名.密码.重复密码.邮箱.qq.手机号码.爱好.学历 具体步骤: 制作表单 表单form数据通过create()方法收集(验证功能要求我们必须通过create( ...
- Linux命令——创建删除文件
创建文件夹 mkdir filename 进入目录文件 cd filename 返回上一级目录 cd ..返回多级目录 cd ../../.. (../表示一级) 创建文件 touch filen ...
- MLlib-协同过滤
协同过滤 显示vs隐式反馈 参数调整 实例 教程 协同过滤 协同过滤是推荐系统的常用方法.可以填充user-item相关矩阵中的缺失值.MLlib支持基于模型的协同过滤,即使用能够预测缺失值的一个隐藏 ...
- uva 10820 (筛法构造欧拉函数)
send a table When participating in programming contests, you sometimes face the following problem: Y ...
- DNS解析原理
1.在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析. 2.如果hosts里没有这个域名的映射,则 ...
- Python的XMLRPC机制:实现跨进程间、client/server端通信
SimpleXMLRPCServer模块式python语言的一个基于 xml 格式的进程间通信的基础框架. SimpleXMLRPCServer是一个单线程的服务器,这意味着,如果几个客户端同时发出多 ...