题目相关
题目链接
AtCoder Beginner Contest 187 B 题,https://atcoder.jp/contests/abc187/tasks/abc187_b。
Problem Statement
On the
x
y
xy
xy-plane, We have
N
N
N points numbered
1
1
1 to
N
N
N. Point
i
i
i is at
(
x
i
,
y
i
)
(x_i,y_i)
(xi,yi), and the
x
x
x-coordinates of the
N
N
N points are pairwise different.
Find the number of pairs of integers
(
i
,
j
)
(
i
<
j
)
(i,j) (i<j)
(i,j)(i<j) that satisfy the following condition:
The line passing through Point
i
i
i and Point
j
j
j has a slope between
−
1
−1
−1 and
1
1
1 (inclusive).
Input
Input is given from Standard Input in the following format:
N
xi yi
.
.
.
xn yn
Output
Print the answer.
Sample 1
Sample Input 1
3
0 0
1 2
2 1
Sample Output 1
2
Explaination
The slopes of the lines passing through ( 0 , 0 ) (0,0) (0,0) and ( 1 , 2 ) (1,2) (1,2), passing through ( 0 , 0 ) (0,0) (0,0) and ( 2 , 1 ) (2,1) (2,1), and passing through ( 1 , 2 ) (1,2) (1,2) and ( 2 , 1 ) (2,1) (2,1) are 2 2 2, 1 2 \frac{1}{2} 21, and − 1 −1 −1, respectively.
Sample 2
Sample Input 2
1
-691 273
Sample Output 2
0
Sample 3
Sample Input 3
10
-31 -35
8 -36
22 64
5 73
-14 8
18 -58
-41 -85
1 -88
-21 -85
-11 82
Sample Output 3
11
Constraints
- All values in input are integers.
- 1 ≤ N ≤ 10^3
- |xi|,|yi| ≤ 10^3
- xi≠xj for i≠j.
题解报告
题目翻译
在
x
y
xy
xy 坐标系中,有
N
N
N 个点,编号为
1
−
N
1 - N
1−N,第
i
i
i 个点的坐标为
(
x
i
,
y
i
)
(x_i, y_i)
(xi,yi),这
N
N
N 个点的坐标各不相同,并且坐标为整数。
请找出有多少个点对
(
i
,
j
)
(
i
<
j
)
(i, j) (i < j)
(i,j)(i<j) 满足以下条件:
1、连接第
i
i
i 和
j
j
j 点的直线斜率在
−
1
-1
−1 和
1
1
1 之间。
题目分析
本题是一个数学题,核心就是如何求两个点组成的直线斜率。
直线斜率
假设我们有两个点
N
i
N_i
Ni 和
N
j
N_j
Nj,满足
i
<
j
i < j
i<j,对应的坐标为
(
x
i
,
y
i
)
(x_i, y_i)
(xi,yi) 和
(
x
j
,
y
j
)
(x_j, y_j)
(xj,yj),如下图所示。
如图所示,通过这两个点的直线的斜率为:
y
j
−
y
i
x
j
−
x
i
\frac{y_j - y_i}{x_j - x_i}
xj−xiyj−yi。
因此,本题就是遍历所有可能的两个点组成的直线,计算其斜率,并判断是否符合题目要求。
改进
由于计算斜率我们不可避免会得到一个浮点数,为了优化,我们可以进一步讨论一下数学问题。
满足要求的斜率为:
−
1
≤
y
j
−
y
i
x
j
−
x
i
≤
1
⇔
∣
y
j
−
y
i
x
j
−
x
i
∣
≤
1
⇔
∣
y
j
−
y
i
∣
≤
∣
x
j
−
x
i
∣
-1 \leq \frac{y_j - y_i}{x_j - x_i} \leq 1 \quad \Leftrightarrow \quad \lvert \frac{y_j - y_i}{x_j - x_i} \rvert \leq 1 \quad \Leftrightarrow \quad \lvert y_j - y_i \rvert \leq \lvert x_j - x_i \rvert
−1≤xj−xiyj−yi≤1⇔∣xj−xiyj−yi∣≤1⇔∣yj−yi∣≤∣xj−xi∣
数据分析
样例数据 1
根据样例数据,我们知道有三个点:
(
0
,
0
)
,
(
1
,
2
)
,
(
2
,
1
)
(0, 0), (1, 2), (2, 1)
(0,0),(1,2),(2,1)。因此可以构成三条直线。
第一条直线,通过点
(
0
,
0
)
(0, 0)
(0,0) 和 点
(
1
,
2
)
(1, 2)
(1,2)。对应的斜率为
2
−
0
1
−
0
=
2
\frac{2-0}{1-0}=2
1−02−0=2。
第二条直线,通过点
(
0
,
0
)
(0, 0)
(0,0) 和 点
(
2
,
1
)
(2, 1)
(2,1)。对应的斜率为
1
−
0
2
−
0
=
1
2
\frac{1-0}{2-0}=\frac{1}{2}
2−01−0=21。
第三条直线,通过点
(
1
,
2
)
(1, 2)
(1,2) 和 点
(
2
,
1
)
(2, 1)
(2,1)。对应的斜率为
1
−
2
2
−
1
=
−
1
\frac{1-2}{2-1}=-1
2−11−2=−1。
因此,符合要求的直线有两条,分别是第二条和第三条。
数据范围分析
N N N 的最大值为 1 0 3 10^3 103,因此使用暴力遍历 O ( N 2 ) O(N^2) O(N2) 可以满足需求。
AC 代码
//https://atcoder.jp/contests/abc187/tasks/abc187_b
//B - Gentle Pairs
#include <bits/stdc++.h>
using namespace std;
//如果提交到OJ,不要定义 __LOCAL
//#define __LOCAL
const int MAXN=1e3+4;
int x[MAXN];
int y[MAXN];
int main() {
#ifndef __LOCAL
//这部分代码需要提交到OJ,本地调试不使用
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
int n;
cin>>n;
for (int i=1; i<=n; i++) {
cin>>x[i]>>y[i];
}
//
int ans=0;
for (int i=1; i<n; i++) {
for (int j=i+1; j<=n; j++) {
if (abs(y[j]-y[i])<=abs(x[j]-x[i])) {
ans++;
}
}
}
cout<<ans<<"\n";
#ifdef __LOCAL
//这部分代码不需要提交到OJ,本地调试使用
system("pause");
#endif
return 0;
}
时间复杂度
O ( N 2 ) O(N^2) O(N2)。
空间复杂度
O ( N ) O(N) O(N)。
和使用浮点数比较代码对比
相同的代码,差距在比较使用浮点数。我们仅仅比对时间。
//https://atcoder.jp/contests/abc187/tasks/abc187_b
//B - Gentle Pairs
#include <bits/stdc++.h>
using namespace std;
//如果提交到OJ,不要定义 __LOCAL
//#define __LOCAL
const int MAXN=1e3+4;
int x[MAXN];
int y[MAXN];
int main() {
#ifndef __LOCAL
//这部分代码需要提交到OJ,本地调试不使用
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#endif
int n;
cin>>n;
for (int i=1; i<=n; i++) {
cin>>x[i]>>y[i];
}
//
int ans=0;
int yy;
int xx;
double slope;
for (int i=1; i<n; i++) {
for (int j=i+1; j<=n; j++) {
yy=y[j]-y[i];
xx=x[j]-x[i];
slope=1.0*yy/xx;
if (slope>=-1 && slope<=1) {
ans++;
}
}
}
cout<<ans<<"\n";
#ifdef __LOCAL
//这部分代码不需要提交到OJ,本地调试使用
system("pause");
#endif
return 0;
}
可以明显的看出,相同的代码,使用浮点数比较需要 15ms,而使用定点数比较,只需要 8ms,速度快了一倍。因此尽量少用浮点数比较。