RPG的地图
题意
判断点是否在不规则多边形内,
分析
首先,所有横、纵坐标都+1000,方便标记和累加。
- 在边上也满足条件,对于垂直或平行于 x 轴的线段,直接在枚举线段的时候标记下其中的所有点即可。对于其它线段,表示成
y = k * x + b
的形式,枚举 x 找到,整数 y 即可。 - 对于在里面的点,通过射线法判断,但是查询的点过多,考虑通过预处理优化,考虑一条垂直于 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;
}