POJ 2318 TOYS 向量叉积运算

题意,给出一块方框的左上、右下角坐标,然后输入n个挡板的两端点坐标(挡板从0~(n-1)标记),再输入m个玩具丢到框内的坐标。数据保证玩具丢到框里,且挡板已经从左到右排好序。输出落在每块挡板前空间内的玩具个数。

类似的方法以前在杭电OJ遇到过,是一道计算多边形面积题目。当时没有学向量积运算,所以最后只是记了个多边形面积公式。POJ 2318这道题,也是叉积运算,恰好今天微积分讲了向量积基础内容,晚上集训队又继续深入了向量积的一些应用,于是这道题可以独立A掉了。

由于输入的数据各种被保证,最终只需要依次计算两点是否在挡板同侧,边界处理、排序什么的全部免掉,当初担心的o(n^2)超时问题,也因为这题数据够水没有发生。当然,较好的办法还是二分查找。

叉乘的另外一些应用,正结合题目学习中,之后继续更新。

 

附上没有二分优化的叉积运算(数据水得可以,590ms过的)

 1 #include<iostream>
2 #include<algorithm>
3 using namespace std;
4
5 const double eps = 1e-8;
6
7 struct Point{
8 double x, y;
9 };
10
11 struct Vector{
12 Point a, b;
13 };
14
15 double xmulti(const Point p1, const Point p2, const Point p0)
16 {
17 return (p1.x - p0.x) * (p2.y - p0.y) - (p1.y - p0.y) * (p2.x - p0.x); //向量叉乘运算
18 }
19
20 bool same_side(const Point p1, const Point p2, const Vector vec)
21 {
22 return xmulti(vec.a, p1, vec.b) * xmulti(vec.a, p2, vec.b) > eps; //判断两点是否在直线同侧
23 }
24
25 int main()
26 {
27 int n, m, first = 1;
28 while(scanf("%d", &n), n)
29 {
30 scanf("%d", &m);
31 int mark[5000] = {0};
32 Point p1, p2, p_Toy, p_Center;
33 Vector *v_Node = new Vector[n];
34 scanf("%lf%lf%lf%lf", &p1.x, &p1.y, &p2.x, &p2.y);
35 p_Center.x = p1.x;
36 p_Center.y = (p1.y + p2.y) / 2;
37 for(int i = 0; i < n; i++)
38 {
39 scanf("%lf%lf", &v_Node[i].a.x, &v_Node[i].b.x);
40 v_Node[i].a.y = p1.y;
41 v_Node[i].b.y = p2.y;
42 }
43 while(m--)
44 {
45 bool find = false;
46 scanf("%lf%lf", &p_Toy.x, &p_Toy.y);
47 for(int j = 0; j < n; j++)
48 {
49 if(same_side(p_Toy, p_Center, v_Node[j]))
50 {
51 mark[j]++, find = true; //挡板已经排列好,只要玩具第一次出现在挡板左侧即可结束
52 break;
53 }
54 }
55 if(!find)
56 {
57 mark[n]++; //注意如果没有落在中间的挡板内,根据题意,只能落在最后一块挡板和右边边缘中间了
58 }
59 }
60 if(!first)
61 {
62 printf("\n");
63 }
64 first = 0;
65 for(int i = 0; i <= n; i++)
66 {
67 printf("%d: %d\n", i, mark[i]);
68 }
69 delete[] v_Node;
70 v_Node = NULL;
71 }
72 return 0;
73 }


 

posted @ 2012-02-21 22:26  dgsrz  阅读(979)  评论(0编辑  收藏  举报