CodeChef---- February Challenge 2018----Points Inside A Polygon
链接:https://www.codechef.com/FEB18/problems/POINPOLY
Points Inside A Polygon Problem Code: POINPOLY
You have to find any ⌊N/10⌋ distinct points with integer coordinates that lie strictly insidethe polygon, or determine that such a set of points doesn't exist.
Note: ⌊⌋ denotes the floor function, typically used in integer division.
Input
- The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
- The first line of each test case contains a single integer N denoting the number of vertices of the polygon.
- The following N lines describe the vertices of the polygon in anticlockwise order. Each of these lines contains two space-separated integers x and y denoting the coordinates of one vertex.
Output
For each test case, if a valid set of points doesn't exist, print a single line containing the integer -1. Otherwise, print ⌊N/10⌋ lines. Each of these lines should contain two space-separated integers denoting the coordinates of one point.
The coordinates of all points should be integers with absolute value not exceeding 109. If there are multiple solutions, you may print any one.
Constraints
- 1 ≤ T ≤ 105
- 10 ≤ N ≤ 105
- sum of N over all test cases ≤ 5 · 105
- |x|, |y| ≤ 109
- no three vertices of the polygon will be collinear
Subtasks
Subtask #1 (30 points): 1 ≤ T ≤ 100, 10 ≤ N ≤ 100
Subtask #2 (70 points): original constraints
Example
Input 1
11
0 0
1 1
2 3
2 5
0 10
-2 10
-5 9
-8 7
-8 4
-6 1
-2 0 Output 0 1
////////////////////////////////////////////////////////////
看到这道题是一脸懵逼的,后来想着在每个端点附近是有四个点,至少有一个点在凸包内,最多每三个点共享一个凸包内相邻点,于是肯定可以做
那么对于一个点,怎么判断是否在凸包内呢,我是把每个端点求出跟左右两点的直线方程式(o1求)然后先对于每一个端点,对于凸包的端点,判断是在每一条线的那一侧(根据方程式用正负值来表示)
(但是不可能n²来求得对每个点来说,凸包端点是在线的哪一侧,所以我去了最上下左右四个点,用于判断,只要四个点是不同的,肯定至少有一个点跟判定点不共线,就可以求得是在哪一侧,后来发现出bug了
就是当最上下左右四个点指向的是两个点的时候,代码是有bug的,错误的例子就是左下右上处在最上下左右,这时候需要特判一下,如果出现了,将相同的值换成另外一个其他点就行了)
然后对于某个端点相邻的点,求出他在两条线的哪一侧,如果跟凸包端点都相同,那就是在凸包内了,后来想着,几十个点围成一个宽为1的正方形不就gg了,所以还加了对于上下左右四个点是否也符合条件
(后来问了zk的做法之后,发现,原来凸包是没有三点共线的吗,,,emmm我好菜)(前面会出现那个地方会出bug也是因为加了上下左右点的判定,但是这四个点集中在两个点的话,如果两点相邻,那么他们的方向值就是 0 0,这样
任何点都会被判定成不符合)
然后贴个自己的代码
///////////////////////////////////////////////////////////////////////////
#include <bits/stdc++.h>
#define mst(a,b) memset((a),(b), sizeof a)
#define lowbit(a) ((a)&(-a))
#define IOS ios::sync_with_stdio(0);cin.tie(0);
using namespace std;
typedef long long ll;
const int mod=1e9+;
const int maxn=1e5+;
int n;
struct point{int x,y;};
struct line{ll a,b,c;};
point po[maxn];
line li[maxn][];
int cc[maxn][];
int dx[]={,,-,},dy[]={,-,,};
vector<pair<int,int> >ans;
int up=1e5+,down=1e5+,le=1e5+,ri=1e5+;
void gtline(int i,int j,line& k){
k.a=po[i].y-po[j].y;
k.b=po[j].x-po[i].x;
k.c=(ll)po[i].x*po[j].y-(ll)po[j].x*po[i].y;
} int dir(line&k,int x,int y){
ll g=k.a*x+k.b*y+k.c;
if(g==)return ;
if(g<)return -;
return ;
}
bool gg(int p,int x,int y){
if(dir(li[p][],x,y)!=cc[p][])return true;
if(dir(li[p][],x,y)!=cc[p][])return true;
return false;
}
bool ok(int p,int x,int y){
if(gg(p,x,y))return false;
if(gg(le,x,y))return false;
if(gg(ri,x,y))return false;
if(gg(up,x,y))return false;
if(gg(down,x,y))return false;
return true;
}
void co(){
int ne=n/;
set<pair<int,int> >use;
vector<int>kk;
if(ans.size()<ne){printf("-1\n");return;}
for(int i=;i<ans.size();++i){
if(!use.count(ans[i])){
use.insert(ans[i]);
kk.push_back(i);
--ne;
if(!ne)break;
}
}
if(ne){printf("-1\n");return;}
for(int i=;i<kk.size();++i){
printf("%d %d\n",ans[kk[i]].first,ans[kk[i]].second);
} }
void check(){
if(up==ri||up==le){
int tmp=1e5+;
for(int i=;i<n;++i)if(i!=ri&&i!=le){
if(po[i].y>po[tmp].y)tmp=i;
}
up=tmp;
}
if(down==ri||down==le){
int tmp=1e5+;
for(int i=;i<n;++i)if(i!=ri&&i!=le){
if(po[i].y<po[tmp].y)tmp=i;
}
down=tmp;
}
}
int main(){
#ifdef local
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
int t;scanf("%d",&t);
po[up].y=-1e9-;po[down].y=1e9+;po[le].x=1e9+;po[ri].x=-1e9-;
while(t--){
up=1e5+,down=1e5+,le=1e5+,ri=1e5+;
scanf("%d",&n);
for(int i=;i<n;++i){
scanf("%d%d",&po[i].x,&po[i].y);
if(po[i].x<po[le].x)le=i;
if(po[i].x>po[ri].x)ri=i;
if(po[i].y>po[up].y)up=i;
if(po[i].y<po[down].y)down=i;
}
check();
for(int i=;i<n;++i){
for(int j=;j<;++j){
int ad=(j==?-:);
gtline(i,(i+ad+n)%n,li[i][j]);cc[i][j]=;
cc[i][j]=dir(li[i][j],po[le].x,po[le].y);
if(!cc[i][j])
cc[i][j]=dir(li[i][j],po[ri].x,po[ri].y);
if(!cc[i][j])
cc[i][j]=dir(li[i][j],po[up].x,po[up].y);
if(!cc[i][j])
cc[i][j]=dir(li[i][j],po[down].x,po[down].y);
}
}
ans.clear();
for(int i=;i<n;++i){
for(int j=;j<;++j){
if(ok(i,po[i].x+dx[j],po[i].y+dy[j])){
ans.push_back(make_pair(po[i].x+dx[j],po[i].y+dy[j]));
break;
}
}
}
co();
}
return ;
}
zk 的做法是根据端点坐标的奇偶性分成四类,这样数量最多的一类至少有n/4个点(鸽笼原理),然后因为三点不共线,由于凸包每两个端点的中点一定在凸包内,或是在端点连线上(两点相邻)
由于三点不共线,所以,做多那个类以至少可以产出n/4-2个端点,这个极限情况只有当n==10可能出现,实际能够产出点应该是(n/4)²级别的(这是我猜的)
然后放一下根据zk的解法写的代码(瞬间短了很多)
//////////////////////////////////////////////////////////////
#include <bits/stdc++.h>
#define mst(a,b) memset((a),(b), sizeof a)
#define lowbit(a) ((a)&(-a))
#define IOS ios::sync_with_stdio(0);cin.tie(0);
using namespace std;
typedef long long ll;
const int mod=1e9+;
const int maxn=1e5+;
int x[maxn],y[maxn];
vector<int>has[][];
vector<pair<int,int> >ans;
set<pair<int,int> >uu;
int main(){
#ifdef local
freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
#endif
int t;scanf("%d",&t);
while(t--){
int n;scanf("%d",&n);
for(int i=;i<;++i)for(int j=;j<;++j)has[i][j].clear();
for(int i=;i<n;++i){
scanf("%d%d",&x[i],&y[i]);
has[abs(x[i])%][abs(y[i])%].push_back(i);
}
int a=,b=;
for(int i=;i<;++i)for(int j=;j<;++j)
if(has[i][j].size()>has[a][b].size())a=i,b=j;
int ne=n/; ans.clear(); uu.clear();
for(int i=;i<has[a][b].size();++i){
for(int j=i+;j<has[a][b].size();++j){
int l=has[a][b][i],r=has[a][b][j];
if(l+==r||l==&&r==n-)continue;
int mx=(x[l]+x[r])>>,my=(y[l]+y[r])>>;
if(!uu.count(make_pair(mx,my))){
ans.push_back(make_pair(mx,my));
uu.insert(make_pair(mx,my));
--ne;
}
if(!ne)break;
}
if(!ne)break;
}
for(int i=;i<ans.size();++i)printf("%d %d\n",ans[i].first,ans[i].second);
}
return ;
}
安慰一下自己emm我的代码比zk的多适用与正方性那种样例(非凸包)orz
CodeChef---- February Challenge 2018----Points Inside A Polygon的更多相关文章
- CodeChef February Challenge 2018 Points Inside A Polygon (鸽笼原理)
题目链接 Points Inside A Polygon 题意 给定一个$n$个点的凸多边形,求出$[ \frac{n}{10}]\ $个凸多边形内的整点. 把$n$个点分成$4$类: 横坐标奇, ...
- codechef February Challenge 2018 简要题解
比赛链接:https://www.codechef.com/FEB18,题面和提交记录是公开的,这里就不再贴了 Chef And His Characters 模拟题 Chef And The Pat ...
- CodeChef February Challenge 2018 Broken Clock (三角函数推导 + 矩阵快速幂)
题目链接 Broken Clock 中文题面链接 令$cos(xα) = f(x)$ 根据三角函数变换公式有 $f(x) = \frac{2d}{l} f(x-1) - f(x-2)$ 我们现在 ...
- Codechef October Challenge 2018 游记
Codechef October Challenge 2018 游记 CHSERVE - Chef and Serves 题目大意: 乒乓球比赛中,双方每累计得两分就会交换一次发球权. 不过,大厨和小 ...
- Codechef September Challenge 2018 游记
Codechef September Challenge 2018 游记 Magician versus Chef 题目大意: 有一排\(n(n\le10^5)\)个格子,一开始硬币在第\(x\)个格 ...
- Codechef STMINCUT S-T Mincut (CodeChef May Challenge 2018) kruskal
原文链接http://www.cnblogs.com/zhouzhendong/p/9010945.html 题目传送门 - Codechef STMINCUT 题意 在一个有边权的无向图中,我们定义 ...
- Codechef August Challenge 2018 : Chef at the River
传送门 (要是没有tjm(Sakits)的帮忙,我还真不知道啥时候能做出来 结论是第一次带走尽可能少的动物,使未带走的动物不冲突,带走的这个数量就是最优解. 首先这个数量肯定是下界,更少的话连第一次都 ...
- Codechef August Challenge 2018 : Safe Partition
传送门 (虽然是A了但是不知道复杂度是不是正确的 考虑以某个位置为结尾的合法划分 先考虑min,带来的影响是限制了最小长度,预处理出这个最小长度后,这可以在处理到这个数时,把不能算的部分去掉(不满足m ...
- Codechef August Challenge 2018 : Interactive Matrix
传送门 首先整个矩阵可以被分为很多小矩阵,小矩阵内所有行的单调性是一样的,所有列的单调性是一样的. 考虑如何在这样一个小矩阵中找出答案.我的策略是每次取四个角中最大值和最小值的点,这样可以每次删掉一行 ...
- Codechef August Challenge 2018 : Lonely Cycles
传送门 几波树形dp就行了. #include<cstdio> #include<cstring> #include<algorithm> #define MN 5 ...
随机推荐
- 洛谷 P5239 回忆京都 题解
题面 裸的杨辉三角前缀和,但----- 在求前缀和的时候有可能得到一个负数(由于取模的原因),所以一定要加上模数后再取模!!!! #include <bits/stdc++.h> #def ...
- MySQL总结(4)
insert 数据的插入 INSERT插入数据
- 怎么编写properties文件
1. 注释 在properties中注释是采用#号开头的方式来进行注释的 2. 编写properties文件 在properties中,一行就是一个键值对,简单的理解就是一行可以保存一个变量,键和值之 ...
- vue在组件中使用v-model
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 关于Unsupported major.minor version 52.0报错问题解决方案
目录 1.问题描述2.问题分析3.解决方案步骤一:删除JDK1.7版本步骤二:导入JDK1.8版本步骤三:将新的JDK1.8引入到工程中4.总结1.问题描述在启动项目工程中,当编译class文件的时候 ...
- Java函数优雅之道
https://www.cnblogs.com/amap_tech/p/11320171.html 导读 随着软件项目代码的日积月累,系统维护成本变得越来越高,是所有软件团队面临的共同问题.持续地优化 ...
- aria2的安装与配置
aria2安装 安装 epel 源: yum install epel-release 然后直接安装: yum install aria2 -y 配置 Aria2 创建目录与配置文件 这一步需要切换到 ...
- tensorflow中张量_常量_变量_占位符
1.tensor 在tensorflow中,数据是被封装在tensor对象中的.tensor是张量的意思,即包含从0到任意维度的张量.常数是0维度的张量,向量是1维度的张量,矩阵是二维度的张量,以及还 ...
- php随机获取数组里面的值
srand() 函数播下随机数发生器种子,array_rand() 函数从数组中随机选出一个或多个元素,并返回.第二个参数用来确定要选出几个元素.如果选出的元素不止一个,则返回包含随机键名的数组,否则 ...
- 并查集 || [USACO18JAN]MooTube || BZOJ 5188 || Luogu P4185
题面:[USACO18JAN]MooTube 题解: 对边和询问都排序,然后每次把符合当前要求的边都扔并查集里,对于每个询问判断当前并查集里节点数即可. 我很无聊地给并查集加了按秩排序,还开了O2,加 ...