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,这样
任何点都会被判定成不符合)
然后贴个自己的代码
///////////////////////////////////////////////////////////////////////////
  1 #include <bits/stdc++.h>
  2 #define mst(a,b)    memset((a),(b), sizeof a)
  3 #define lowbit(a)   ((a)&(-a))
  4 #define IOS         ios::sync_with_stdio(0);cin.tie(0);
  5 using namespace std;
  6 typedef long long ll;
  7 const int mod=1e9+7;
  8 const int maxn=1e5+10;
  9 int n;
 10 struct point{int x,y;};
 11 struct line{ll a,b,c;};
 12 point po[maxn];
 13 line li[maxn][2];
 14 int cc[maxn][2];
 15 int dx[]={0,0,-1,1},dy[]={1,-1,0,0};
 16 vector<pair<int,int> >ans;
 17 int up=1e5+2,down=1e5+3,le=1e5+4,ri=1e5+5;
 18 void gtline(int i,int j,line& k){
 19     k.a=po[i].y-po[j].y;
 20     k.b=po[j].x-po[i].x;
 21     k.c=(ll)po[i].x*po[j].y-(ll)po[j].x*po[i].y;
 22 }
 23  
 24 int dir(line&k,int x,int y){
 25     ll g=k.a*x+k.b*y+k.c;
 26     if(g==0)return 0;
 27     if(g<0)return -1;
 28     return 1;
 29 }
 30 bool gg(int p,int x,int y){
 31     if(dir(li[p][0],x,y)!=cc[p][0])return true;
 32     if(dir(li[p][1],x,y)!=cc[p][1])return true;
 33     return false;
 34 }
 35 bool ok(int p,int x,int y){
 36     if(gg(p,x,y))return false;
 37     if(gg(le,x,y))return false;
 38     if(gg(ri,x,y))return false;
 39     if(gg(up,x,y))return false;
 40     if(gg(down,x,y))return false;
 41     return true;
 42 }
 43 void co(){
 44     int ne=n/10;
 45     set<pair<int,int> >use;
 46     vector<int>kk;
 47     if(ans.size()<ne){printf("-1\n");return;}
 48     for(int i=0;i<ans.size();++i){
 49         if(!use.count(ans[i])){
 50             use.insert(ans[i]);
 51             kk.push_back(i);
 52             --ne;
 53             if(!ne)break;
 54         }
 55     }
 56     if(ne){printf("-1\n");return;}
 57     for(int i=0;i<kk.size();++i){
 58         printf("%d %d\n",ans[kk[i]].first,ans[kk[i]].second);
 59     }
 60  
 61 }
 62 void check(){
 63     if(up==ri||up==le){
 64         int tmp=1e5+2;
 65         for(int i=0;i<n;++i)if(i!=ri&&i!=le){
 66             if(po[i].y>po[tmp].y)tmp=i;
 67         }
 68         up=tmp;
 69     }
 70     if(down==ri||down==le){
 71         int tmp=1e5+3;
 72         for(int i=0;i<n;++i)if(i!=ri&&i!=le){
 73             if(po[i].y<po[tmp].y)tmp=i;
 74         }
 75         down=tmp;
 76     }
 77 }
 78 int main(){
 79 #ifdef local
 80 freopen("in.txt","r",stdin);
 81 //freopen("out.txt","w",stdout);
 82 #endif
 83     int t;scanf("%d",&t);
 84     po[up].y=-1e9-10;po[down].y=1e9+10;po[le].x=1e9+10;po[ri].x=-1e9-10;
 85     while(t--){
 86         up=1e5+2,down=1e5+3,le=1e5+4,ri=1e5+5;
 87         scanf("%d",&n);
 88         for(int i=0;i<n;++i){
 89             scanf("%d%d",&po[i].x,&po[i].y);
 90             if(po[i].x<po[le].x)le=i;
 91             if(po[i].x>po[ri].x)ri=i;
 92             if(po[i].y>po[up].y)up=i;
 93             if(po[i].y<po[down].y)down=i;
 94         }
 95         check();
 96         for(int i=0;i<n;++i){
 97             for(int j=0;j<2;++j){
 98                 int ad=(j==0?-1:1);
 99                 gtline(i,(i+ad+n)%n,li[i][j]);cc[i][j]=0;
100                 cc[i][j]=dir(li[i][j],po[le].x,po[le].y);
101                 if(!cc[i][j])
102                     cc[i][j]=dir(li[i][j],po[ri].x,po[ri].y);
103                 if(!cc[i][j])
104                     cc[i][j]=dir(li[i][j],po[up].x,po[up].y);
105                 if(!cc[i][j])
106                     cc[i][j]=dir(li[i][j],po[down].x,po[down].y);
107             }
108         }
109         ans.clear();
110         for(int i=0;i<n;++i){
111             for(int j=0;j<4;++j){
112                 if(ok(i,po[i].x+dx[j],po[i].y+dy[j])){
113                     ans.push_back(make_pair(po[i].x+dx[j],po[i].y+dy[j]));
114                     break;
115                 }
116             }
117         }
118         co();
119     }
120     return 0;
121 }

zk 的做法是根据端点坐标的奇偶性分成四类,这样数量最多的一类至少有n/4个点(鸽笼原理),然后因为三点不共线,由于凸包每两个端点的中点一定在凸包内,或是在端点连线上(两点相邻)

由于三点不共线,所以,做多那个类以至少可以产出n/4-2个端点,这个极限情况只有当n==10可能出现,实际能够产出点应该是(n/4)²级别的(这是我猜的)

然后放一下根据zk的解法写的代码(瞬间短了很多)

//////////////////////////////////////////////////////////////

 1 #include <bits/stdc++.h>
 2 #define mst(a,b)    memset((a),(b), sizeof a)
 3 #define lowbit(a)   ((a)&(-a))
 4 #define IOS         ios::sync_with_stdio(0);cin.tie(0);
 5 using namespace std;
 6 typedef long long ll;
 7 const int mod=1e9+7;
 8 const int maxn=1e5+10;
 9 int x[maxn],y[maxn];
10 vector<int>has[2][2];
11 vector<pair<int,int> >ans;
12 set<pair<int,int> >uu;
13 int main(){
14 #ifdef local
15 freopen("in.txt","r",stdin);
16 //freopen("out.txt","w",stdout);
17 #endif
18     int t;scanf("%d",&t);
19     while(t--){
20         int n;scanf("%d",&n);
21         for(int i=0;i<2;++i)for(int j=0;j<2;++j)has[i][j].clear();
22         for(int i=0;i<n;++i){
23             scanf("%d%d",&x[i],&y[i]);
24             has[abs(x[i])%2][abs(y[i])%2].push_back(i);
25         }
26         int a=0,b=0;
27         for(int i=0;i<2;++i)for(int j=0;j<2;++j)
28         if(has[i][j].size()>has[a][b].size())a=i,b=j;
29         int ne=n/10;    ans.clear();    uu.clear();
30         for(int i=0;i<has[a][b].size();++i){
31             for(int j=i+1;j<has[a][b].size();++j){
32                 int l=has[a][b][i],r=has[a][b][j];
33                 if(l+1==r||l==0&&r==n-1)continue;
34                 int mx=(x[l]+x[r])>>1,my=(y[l]+y[r])>>1;
35                 if(!uu.count(make_pair(mx,my))){
36                     ans.push_back(make_pair(mx,my));
37                     uu.insert(make_pair(mx,my));
38                     --ne;
39                 }
40                 if(!ne)break;
41             }
42             if(!ne)break;
43         }
44         for(int i=0;i<ans.size();++i)printf("%d %d\n",ans[i].first,ans[i].second);
45     }
46     return 0;
47 }

安慰一下自己emm我的代码比zk的多适用与正方性那种样例(非凸包)orz

posted on 2018-02-08 16:08  scau_bi  阅读(271)  评论(0编辑  收藏  举报

导航