坐标(Py/Java/C++/Js/Go)题解
美团研发岗 四月十八号笔试 第二题
题目内容
在二维直角坐标系中有 nnn 个点(按输入顺序编号为 111∼nnn),每个点的横、纵坐标均为整数。
请你构造一个大小为 n×nn×nn×n 的数组 {ai,ja_{i,j}ai,j}。对任意两个不同的编号i,ji,ji,j,将线段 ijijij 围绕点 iii 旋转一周,线段的另一端点在以 iii 为圆心、半径为 ∣ij∣∣ij∣∣ij∣ 的圆盘上运动。定义ai,ja_{i,j}ai,j 为线段 ijijij 在旋转过程中扫过的区域(即以iii 为圆心、半径为 ∣ij∣∣ij∣∣ij∣ 的圆盘)内包含的、除 i,ji,ji,j 之外其他编号不同的点的数量;特别地,对所有1≤i≤n1≤i≤n1≤i≤n都有 ai,i=0a_{i,i}=0ai,i=0。
更形式化地,令点iii的坐标为 (xi,yi)(x_i,y_i)(xi,yi),则:
ai,j=#{k∈{1,...,n}∖{i,j}∣dist(i,k)≤dist(i,j)}.a_{i,j} = \# \left\{ k \in \{1,\dots,n\} \setminus \{i,j\} \mid \operatorname{dist}(i,k) \le \operatorname{dist}(i,j) \right\}.ai,j=#{k∈{1,...,n}∖{i,j}∣dist(i,k)≤dist(i,j)}.
输入描述
每个测试文件包含多组测试数据:第一行输入一个整数T(1≤T≤102)T(1≤T≤10^2)T(1≤T≤102),代表数据组数。每组测试数据描述如下:
- 第一行输入一个整数 n(1≤n≤2×103)n(1≤n≤2×10^3)n(1≤n≤2×103),表示点的数量。
- 此后共 nnn 行,每行输入两个整数 x,y(1≤x,y≤109)x,y(1≤x,y≤10^9)x,y(1≤x,y≤109),表示一个点的坐标,按输入顺序依次编号为 1,2,...,n1,2,...,n1,2,...,n。
除此之外,保证单个测试文件的 nnn 之和不超过 2×1032×10^32×103。
输出描述
对于每一组测试数据,输出nnn 行:
- 第iii行输出 nnn 个整数,依次为 ai,1,ai,2,...,ai,na_{i,1},a_{i,2},...,a_{i,n}ai,1,ai,2,...,ai,n;
- 数与数之间以一个空格分隔。
样例1
输入
2
3
1 1
2 1
1 2
4
1 1
2 1
3 1
4 1
输出
0 1 1
0 0 1
0 1 0
0 0 1 2
1 0 1 2
2 1 0 1
2 1 0 0
题解
思路
逻辑分析
- 对于每组数据,预处理计算所有点之间
距离的平分 - 从前往后枚举点作为圆心,基于
圆心相同,半径越大,包含点越多的规律。- 将除本身点以
{距离、下标}格式用数组进行保存,然后根据距离对数组进行排序。 - 接下来按照
距离批次进行处理,对于距离为d的包含的点的数量 =与圆心距离距离小于d的数量 + 等于d的点数量
- 将除本身点以
- 按照2的逻辑就能正确计算出对应结果。
C++
cpp
#include<bits/stdc++.h>
using namespace std;
vector<vector<int>> solve(vector<pair<long,long>>& points) {
int n = points.size();
vector<vector<int>> ans(n, vector<int>(n, 0));
// 预处理,统计各个点之间平方距离
vector<vector<long>> dist(n, vector<long>(n, 0));
// 对称的只需计算左下角
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
long dx = points[i].first - points[j].first;
long dy = points[i].second - points[j].second;
dist[i][j] = dx * dx + dy * dy;
dist[j][i] = dist[i][j];
}
}
// 枚举 圆心, 圆心相同,半径越大,包含点越多
for (int i = 0; i < n; i++) {
vector<pair<long, int>> node;
for (int j = 0; j < n; j++) {
// 不考虑本身
if (i == j) {
continue;
}
node.push_back({dist[i][j], j});
}
sort(node.begin(), node.end(), [](auto& a, auto & b) {
return a.first < b.first;
});
// 按照相同距离进行批处理
int m = node.size();
int l = 0;
while (l < m) {
int r = l;
while (r + 1 < m && node[r + 1].first == node[r].first) {
r++;
}
// [l, r]距离相同包含点相同都为r
for (int j = l; j <= r; j++) {
ans[i][node[j].second] = r;
}
l++;
}
}
return ans;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<pair<long, long>> points(n);
for (int i = 0; i < n; i++) {
cin >> points[i].first >> points[i].second;
}
vector<vector<int>> ans = solve(points);
// 输出答案矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (j > 0) {
cout << ' ';
}
cout << ans[i][j];
}
cout << endl;
}
}
return 0;
}
java
java
import java.io.*;
import java.util.*;
public class Main {
static int[][] solve(long[][] points) {
int n = points.length;
int[][] ans = new int[n][n];
// 预处理,统计各个点之间平方距离
long[][] dist = new long[n][n];
// 对称的只需计算左下角
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
long dx = points[i][0] - points[j][0];
long dy = points[i][1] - points[j][1];
dist[i][j] = dx * dx + dy * dy;
dist[j][i] = dist[i][j];
}
}
// 枚举圆心,圆心相同,半径越大,包含点越多
for (int i = 0; i < n; i++) {
List<long[]> node = new ArrayList<>();
for (int j = 0; j < n; j++) {
// 不考虑本身
if (i == j) {
continue;
}
node.add(new long[]{dist[i][j], j});
}
node.sort((a, b) -> Long.compare(a[0], b[0]));
// 按照相同距离进行批处理
int m = node.size();
int l = 0;
while (l < m) {
int r = l;
while (r + 1 < m && node.get(r + 1)[0] == node.get(r)[0]) {
r++;
}
// [l, r]距离相同包含点相同都为r
for (int j = l; j <= r; j++) {
ans[i][(int) node.get(j)[1]] = r;
}
l = r + 1;
}
}
return ans;
}
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringBuilder out = new StringBuilder();
int T = Integer.parseInt(br.readLine());
while (T-- > 0) {
int n = Integer.parseInt(br.readLine());
long[][] points = new long[n][2];
for (int i = 0; i < n; i++) {
String[] arr = br.readLine().split(" ");
points[i][0] = Long.parseLong(arr[0]);
points[i][1] = Long.parseLong(arr[1]);
}
int[][] ans = solve(points);
// 输出答案矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (j > 0) {
out.append(' ');
}
out.append(ans[i][j]);
}
out.append('\n');
}
}
System.out.print(out);
}
}
python
python
import sys
input = sys.stdin.readline
def solve(points):
n = len(points)
ans = [[0] * n for _ in range(n)]
# 预处理,统计各个点之间平方距离
dist = [[0] * n for _ in range(n)]
# 对称的只需计算左下角
for i in range(n):
for j in range(i):
dx = points[i][0] - points[j][0]
dy = points[i][1] - points[j][1]
dist[i][j] = dx * dx + dy * dy
dist[j][i] = dist[i][j]
# 枚举圆心,圆心相同,半径越大,包含点越多
for i in range(n):
node = []
for j in range(n):
# 不考虑本身
if i == j:
continue
node.append((dist[i][j], j))
node.sort()
# 按照相同距离进行批处理
m = len(node)
l = 0
while l < m:
r = l
while r + 1 < m and node[r + 1][0] == node[r][0]:
r += 1
# [l, r]距离相同包含点相同都为r
for j in range(l, r + 1):
ans[i][node[j][1]] = r
l = r + 1
return ans
T = int(input())
for _ in range(T):
n = int(input())
points = []
for _ in range(n):
x, y = map(int, input().split())
points.append((x, y))
ans = solve(points)
# 输出答案矩阵
for row in ans:
print(*row)
javascript
js
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const input = [];
rl.on("line", (line) => {
input.push(line.trim());
});
rl.on("close", () => {
let idx = 0;
const T = Number(input[idx++]);
function solve(points) {
const n = points.length;
const ans = Array.from({ length: n }, () => Array(n).fill(0));
// 预处理,统计各个点之间平方距离
const dist = Array.from({ length: n }, () => Array(n).fill(0));
// 对称的只需计算左下角
for (let i = 0; i < n; i++) {
for (let j = 0; j < i; j++) {
const dx = points[i][0] - points[j][0];
const dy = points[i][1] - points[j][1];
dist[i][j] = dx * dx + dy * dy;
dist[j][i] = dist[i][j];
}
}
// 枚举圆心,圆心相同,半径越大,包含点越多
for (let i = 0; i < n; i++) {
const node = [];
for (let j = 0; j < n; j++) {
// 不考虑本身
if (i === j) {
continue;
}
node.push([dist[i][j], j]);
}
node.sort((a, b) => a[0] - b[0]);
// 按照相同距离进行批处理
const m = node.length;
let l = 0;
while (l < m) {
let r = l;
while (r + 1 < m && node[r + 1][0] === node[r][0]) {
r++;
}
// [l, r]距离相同包含点相同都为r
for (let j = l; j <= r; j++) {
ans[i][node[j][1]] = r;
}
l = r + 1;
}
}
return ans;
}
const output = [];
for (let tc = 0; tc < T; tc++) {
const n = Number(input[idx++]);
const points = [];
for (let i = 0; i < n; i++) {
const [x, y] = input[idx++].split(" ").map(Number);
points.push([x, y]);
}
const ans = solve(points);
// 输出答案矩阵
for (let i = 0; i < n; i++) {
output.push(ans[i].join(" "));
}
}
console.log(output.join("\n"));
});
Go
go
package main
import (
"bufio"
"fmt"
"os"
"sort"
)
func solve(points [][2]int64) [][]int {
n := len(points)
ans := make([][]int, n)
for i := range ans {
ans[i] = make([]int, n)
}
// 预处理,统计各个点之间平方距离
dist := make([][]int64, n)
for i := range dist {
dist[i] = make([]int64, n)
}
// 对称的只需计算左下角
for i := 0; i < n; i++ {
for j := 0; j < i; j++ {
dx := points[i][0] - points[j][0]
dy := points[i][1] - points[j][1]
dist[i][j] = dx*dx + dy*dy
dist[j][i] = dist[i][j]
}
}
type Pair struct {
dist int64
idx int
}
// 枚举圆心,圆心相同,半径越大,包含点越多
for i := 0; i < n; i++ {
node := make([]Pair, 0, n-1)
for j := 0; j < n; j++ {
// 不考虑本身
if i == j {
continue
}
node = append(node, Pair{dist[i][j], j})
}
sort.Slice(node, func(a, b int) bool {
return node[a].dist < node[b].dist
})
// 按照相同距离进行批处理
m := len(node)
l := 0
for l < m {
r := l
for r+1 < m && node[r+1].dist == node[r].dist {
r++
}
// [l, r]距离相同包含点相同都为r
for j := l; j <= r; j++ {
ans[i][node[j].idx] = r
}
l = r + 1
}
}
return ans
}
func main() {
in := bufio.NewReader(os.Stdin)
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
var T int
fmt.Fscan(in, &T)
for ; T > 0; T-- {
var n int
fmt.Fscan(in, &n)
points := make([][2]int64, n)
for i := 0; i < n; i++ {
fmt.Fscan(in, &points[i][0], &points[i][1])
}
ans := solve(points)
// 输出答案矩阵
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
if j > 0 {
fmt.Fprint(out, " ")
}
fmt.Fprint(out, ans[i][j])
}
fmt.Fprintln(out)
}
}
}