【计蒜客】红黑点

来源:互联网 发布:linux 文件改名字 编辑:程序博客网 时间:2024/04/25 08:52

题目


在二维平面有 n 个红点和 m 个黑点,已知这些点的坐标,这些点不存在三点共线的情况。从这些红点中任意取出三个点,可以构成 n * ( n - 1 ) * ( n - 2 ) / 6 个三角形,求这些三角形中包含黑点的数量为奇数的三角形的数量。

输入格式
输入包含多组测试数据,对于每组测试数据:
第一行包含两个整数 n m ( 3 ≤ n ≤ 100 ; 0 ≤ m ≤ 1000 ) 。
接下来 n 行每行包含两个整数,表示 n 个红点的坐标。
接下来 m 行每行包含两个整数,表示 m 个黑点的坐标。
输入保证所有的坐标值的绝对值小于等于 100000 。

输出格式
对于每组测试数据,输出 “Case c: ans” ,其中 c 表示测试数据编号, ans 表示包含奇数个黑点的三角形的数量。
样例输入
4 5
0 0
10 0
0 10
10 10
1 2
3 4
6 2
9 5
6 7
样例输出
Case 1: 2


思路


根据题目所说我们将所有的红色点都将构成三角形并且我们判断黑色的点是否在三角形内部,然后我们转化如何判断点在三角形内部;
根据数学知识叉乘发来判断点是否在三角形内部

叉乘法


沿着三角形的边按顺时针方向走,判断该点是否在每条边的右边(这可以通过叉乘判断),如果该点在每条边的右边,则在三角形内,否则在三角形外。这个算法只用到了三次叉乘,没有除法运算和三角函数、开根号等运算,所以效率很高,而且精度很高(没有浮点误差)。

即(x1*y2-x2*y1)

设三角形三点A(x1,y1)B(x2,y2)C(x3,y3),已知点M(x,y)

1,先求出三个向量MA,MB,MC.

2,计算MA X MB,MB X MC,MC X MA (X表叉乘)

3,如果此三组的向量叉乘的结果都是同号的(或都正,或都负),即方向相同的,则说明点M在三角形每条边的同侧,即内部。否则必在外部!
具体示例:
A(0,3) B(0,0) C(3,0)

M(1,1)
MA (1,-2)
MB (1,1)
MC (-2,1)

MA X MB = 3
MB X MC = 3
MC X MA = 3

N(3,3)
NA (3,0)
NB (3,3)
NC (0,3)

NA X NB = 9
NB X NC = 9
NC X NA = -9

根据以上规则可判断M点在内 N点在外

下面引入代码


代码


#include<iostream>using namespace std;#define maxn 1000static int cc = 0;int n, m;struct point  //点创建{    float x, y;}p[maxn], b[maxn];bool IsInPology(point xx, point yy, point zz, point b)//判断点是否在内部 x,y,z分别表示三个点,b[]表示黑色点的数据{    point bx, by, bz;    bx.x = b.x - xx.x;    bx.y = b.y - xx.y;    by.x = b.x - yy.x;    by.y = b.y - yy.y;    bz.x = b.x - zz.x;    bz.y = b.y - zz.y;    float t1, t2, t3;//叉乘法    t1 = bx.x*by.y - bx.y*by.x;    t2 = by.x*bz.y - by.y*bz.x;    t3 = bz.x*bx.y - bz.y*bx.x;    if ((t1 >= 0 && t2 >= 0 && t3 >= 0) || (t1 <= 0 && t2 <= 0 && t3 <= 0))return true;    else        return false;}//是否具有奇数个黑色的点bool IsOd(point x, point y, point z, point b[]){    int cnt = 0;//计数器统计黑色点的数量    for (int i = 0; i<m; i++)    {        if (IsInPology(x, y, z, b[i]) == true)cnt++;    }    if (cnt % 2 == 0)return false;    return true;}int main(){    cin >> n >> m;    //红色的点  n    for (int i = 0; i<n; i++)    {        cin >> p[i].x >> p[i].y;    }    //黑色的点  m    for (int i = 0; i<m; i++)    {        cin >> b[i].x >> b[i].y;    }    //取三个点    int numP = n, cnt = 0;    for (int i = 0; i < n - 2; i++)    {        for (int j = i + 1; j < n - 1; j++)        {            for (int k = j + 1; k < n; k++)            {                if (IsOd(p[i], p[j], p[k], b) == true)cnt++;            }        }    }    cout << "Case "<<++cc<<": " << cnt << endl;    return 0;}

转载时,请注明出处,谢谢合作

原创粉丝点击