【牛客网多校】19-7-25-H题 Magic Line

 

链接:https://ac.nowcoder.com/acm/contest/883/H
来源:牛客网

  • 题目描述

There are always some problems that seem simple but is difficult to solve.

ZYB got  N distinct points on a two-dimensional plane. He wants to draw a magic line so that the points will be divided into two parts, and the number of points in each part is the same. There is also a restriction: this line can not pass through any of the points.

Help him draw this magic line.

输入描述:

There are multiple cases. The first line of the input contains a single integer T (1≤T≤10000), indicating the number of cases. 

For each case, the first line of the input contains a single even integer N (2≤N≤1000), the number of points. The following $N$ lines each contains two integers xi,yi (∣xi,yi∣≤1000)
It is guaranteed that the sum of  N over all cases does not exceed 2×105.

输出描述:

For each case, print four integers x1,y1,x2,y2 in a line, representing a line passing through (x1,y1) and (x2,y2). Obviously the output must satisfy (x1,y1)≠(x2,y2).

The absolute value of each coordinate must not exceed 109. It is guaranteed that at least one solution exists. If there are multiple solutions, print any of them.
示例1

输入

1
4
0 1
-1 0
1 0
0 -1

输出

-1 999000000 1 -999000001
 
  •  题意

    给定平面上一系列的点,求一条以(x1,y1),(x2,y2)两点表示的直线将平面分为包含点数量相等的两部分,其中直线不能穿过任何一点。

 

  • 解题思路

    计算几何问题。

    示例中的坐标不是随便得到的,将x、y中其中一方拉长到在109以内尽可能大的数,能让直线尽可能水平或者竖直,由于坐标都为整数,这样取值可以使得直线不穿过任何一点,为方便我们取尽可能水平,即x绝对值尽可能大。应该先以y升序,x降序将这些点排序,然后取中位数的两点,若这两点不在同一水平线上,则将这两点的x值扩大;若这两点在同一水平线上,则先将这两点的y坐标一上一下错开,再扩大x的值。

 

  • 错误代码

    最开始考虑完整穿过其他点的所有情况,将直线直接取在了中位点上,又为了防止穿过点而将所取点向上下左右错开,直到所取两点不在给出点集合中。但这种情况仅仅是保证了我所取到的点不在点集中,并不能保证他们所连直线是否穿过别的点。

    错误代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 struct p
 5 {
 6     ll x,y;
 7 }ps[1002];
 8 bool operator <(struct p a,struct p b)
 9 {
10     if (a.x!=b.x) return a.x<b.x;
11     else return a.y<b.y;
12 }
13 bool operator ==(struct p a,struct p b)
14 {
15     return a.x==b.x&&a.y==b.y;
16 }
17 bool operator !=(struct p a,struct p b)
18 {
19     return a.x!=b.x||a.y!=b.y;
20 }
21 set <struct p> points;
22 bool cmpx(struct p a,struct p b)
23 {
24     return a.x<b.x;
25 }
26 bool cmpy(struct p a,struct p b)
27 {
28     return a.y<b.y;
29 }
30 int main()
31 {
32     ll t,n;
33     scanf("%lld",&t);
34     while(t--){
35         ll x1,y1,x2,y2;
36         scanf("%lld",&n);
37         for (ll i=0;i<n;i++){
38             scanf("%lld %lld",&ps[i].x,&ps[i].y);
39             points.insert(ps[i]);
40         }
41         sort(ps,ps+n,cmpx);
42         x1=ps[n/2-1].x;
43         x2=ps[n/2].x;
44         sort(ps,ps+n,cmpy);
45         y1=ps[n/2-1].y;
46         y2=ps[n/2].y;
47         struct p p1,p2;
48         p1.x=x1;p1.y=y2;
49         p2.x=x2;p2.y=y2;
50         if (p1==p2){
51             (p1.x)--;
52             (p1.y)--;
53             (p2.x)++;
54             (p2.y)++;
55         }
56         while(points.find(p1)!=points.end()||points.find(p2)!=points.end()){
57             (p1.x)--;
58             (p2.x)++;
59         }
60         printf("%lld %lld %lld %lld\n",p1.x,p1.y,p2.x,p2.y);
61     }
62     return 0;
63 }
  • AC代码

    在发现题目的真正做法之后还在另一个地方wa了好多遍,这道题对点的排序也有讲究。先前我们的排序方法是x升序,y升序,但拉长x值的时候是将较大x值向上拉长,较小x值向下拉长。这样选取点的话会造成选取的部分并没有被分开。

    即如果我们选择将较大x值向上拉长,较小x值向下拉长的话,这条直线应该是向右上方倾斜的,将平面分成的是左上和右下的两部分,选取点时也自然应该从下到上,从右到左。

    AC代码如下:

 
     
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 struct p
 5 {
 6     ll x,y;
 7 }ps[1002];
 8 bool cmpx(struct p a,struct p b)
 9 {
10     return a.x<b.x;
11 }
12 bool cmpy(struct p a,struct p b)
13 {
14     if(a.y!=b.y) return a.y<b.y;
15     else return a.x>b.x;
16 }
17 int main()
18 {
19     ll t,n;
20     scanf("%lld",&t);
21     while(t--){
22         ll x1,y1,x2,y2;
23         scanf("%lld",&n);
24         for (ll i=0;i<n;i++){
25             scanf("%lld %lld",&ps[i].x,&ps[i].y);
26         }
27         sort(ps,ps+n,cmpy);
28         x1=(ps[n/2-1].x);
29         y1=ps[n/2-1].y;
30         x2=(ps[n/2].x);
31         y2=ps[n/2].y;
32         x1-=999000000;
33         x2+=999000000;
34         if (y1==y2) {
35             y1-=1;
36             y2+=1;
37         }
38         printf("%lld %lld %lld %lld\n",x1,y1,x2,y2);
39     }
40     return 0;
41 }
 
     

 

 
    

转载于:https://www.cnblogs.com/sixwater6H2O/p/11247568.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值