判断点是否在不规则多边形内(预处理优化)

RPG的地图

题意

判断点是否在不规则多边形内,

分析

首先,所有横、纵坐标都+1000,方便标记和累加。

  1. 在边上也满足条件,对于垂直或平行于 x 轴的线段,直接在枚举线段的时候标记下其中的所有点即可。对于其它线段,表示成 y = k * x + b 的形式,枚举 x 找到,整数 y 即可。
  2. 对于在里面的点,通过射线法判断,但是查询的点过多,考虑通过预处理优化,考虑一条垂直于 x 轴向下的射线,对于每条边,对应的 x ,得到的上面的 y ,比如代入 x ,得到的是小数的 y ,向上取整即可,标记+1,表示这一点即上面的点发出的射线都会与这条线段产生交点,对于垂直于 x 轴的直线要特殊判断。对于一条线段,端点值判断一个。标记数组从下向上累加,预处理出前缀和,表示当前这个点向下发出射线会有几个交点,通过奇偶性(奇数在多边形内,偶数不在)得到答案。

射线法
射线法

code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const ll MOD = 1e9 + 7;
const int MAXN = 1e5 + 5;
const int INF = 1e9;
int x[MAXN], y[MAXN];
int vis[2005][2005];
int bj[2005][2005];
int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m))
    {
        memset(vis, 0, sizeof vis);
        memset(bj, 0, sizeof bj);
        for(int i = 0; i < n; i++)
        {
            scanf("%d%d", &x[i], &y[i]);
            x[i] += 1000;
            y[i] += 1000;
            vis[x[i]][y[i]] = 1;
        }
        x[n] = x[0]; y[n] = y[0];
        x[n + 1] = x[1]; y[n + 1] = y[1];
        for(int i = 1; i <= n; i++)
        {
            int j = i - 1;
            if(x[i] == x[j])
            {
                int mn = min(y[i], y[j]);
                int mx = max(y[i], y[j]);
                for(int k = mn; k <= mx; k++) vis[x[i]][k] = 1;
                if(n > 3)
                {
                    int x1 = (j == 0 ? x[n - 1] : x[j - 1]);
                    int x2 = x[i + 1];
                    if(x1 > x[i] && x2 < x[i]) bj[x[i]][mx + 1]++;
                    if(x1 < x[i] && x2 > x[i]) bj[x[i]][mx + 1]++;
                }
            }
            else if(y[i] == y[j])
            {
                int mn = min(x[i], x[j]);
                int mx = max(x[i], x[j]);
                for(int k = mn; k <= mx; k++)
                {
                    vis[k][y[i]] = 1;
                    if(k != mn && k != mx)
                        bj[k][y[i] + 1]++;
                }
                if(x[i + 1] > x[i] && x[j] < x[i]) bj[x[i]][y[i] + 1]++;
                if(x[i + 1] < x[i] && x[j] > x[i]) bj[x[i]][y[i] + 1]++;
 
            }
            else
            {
                double k = 1.0 * (y[i] - y[j]) / (x[i] - x[j]);
                double b = 1.0 * (x[i] * y[j] - x[j] * y[i]) / (x[i] - x[j]);
                int mn = min(x[i], x[j]);
                int mx = max(x[i], x[j]);
                for(int i = mn; i <= mx; i++)
                {
                    double y1 = i * k + b;
                    int y2 = (int)y1;
                    int y3 = int(ceil(y1));
                    if(i != mn && i != mx)
                    {
                        bj[i][y3]++;
                    }
                    if(y2 == y1)
                    {
                        vis[i][y2] = 1;
                    }
                }
                double y1 = x[i] * k + b;
                int y3 = int(ceil(y1));
                if(x[i + 1] > x[i] && x[j] < x[i]) bj[x[i]][y3]++;
                if(x[i + 1] < x[i] && x[j] > x[i]) bj[x[i]][y3]++;
 
            }
        }
        for(int i = 0; i <= 2000; i++)
        {
            for(int j = 0; j <= 2000; j++)
            {
                bj[i][j + 1] += bj[i][j];
            }
        }
        for(int i = 0; i < m; i++)
        {
            int qx, qy;
            scanf("%d%d", &qx, &qy);
            qx += 1000; qy += 1000;
            int f = vis[qx][qy];
            if(!f)
            {
                f = (bj[qx][qy] & 1);
            }
            puts(f ? "Yes" : "No");
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ftae/p/6791426.html