过道对岗
京东技术岗 9月5号笔试 第二题
题目内容
冷链库房的地坪划成 hhh 行 www 列的格子。货架占住的格子用 # 表示,走得动的过道用 . 表示。夜班要把两根对讲桩立在两块不同 的过道上,让两桩的曼哈顿距离尽量大。格子 (r1,c1)(r_1,c_1)(r1,c1) 与 (r2,c2)(r_2,c_2)(r2,c2) 的曼哈顿距离是 ∣r1−r2∣+∣c1−c2∣|r_1-r_2|+|c_1-c_2|∣r1−r2∣+∣c1−c2∣,按坐标直接算,中间隔着货架也不改这个值。
请给出任意一对能达到最大距离的过道坐标。行号、列号都从 1 开始。保证过道至少有两格。
约束:
1≤\le≤ h,wh,wh,w ≤\le≤2000001≤\le≤ h×wh\times wh×w ≤\le≤200000- 每个格子只可能是
.或# - 过道格子数不少于
2
输入描述
第一行两个整数 hhh、www(1 ≤\le≤ h,wh,wh,w ≤\le≤ 200000),表示行数和列数。
随后 hhh 行,每行一个长度为 www 的字符串,只含 . 与 #。
输出描述
一行四个整数 r1r_1r1、c1c_1c1、r2r_2r2、c2c_2c2,表示两根对讲桩所在过道的行号和列号。
若有多种最大方案,输出任意一种即可。
样例1
输入
3 4
.#..
#..#
..#.
输出
1 1 3 4
说明
过道里 (1,1)(1,1)(1,1) 与 (3,4)(3,4)(3,4) 的曼哈顿距离是 ∣1−3∣+∣1−4∣='5'|1-3|+|1-4|=`5`∣1−3∣+∣1−4∣='5',已经是最大。(1,4)(1,4)(1,4) 与 (3,1)(3,1)(3,1) 距离同样是 5,输出那一组也对。
样例2
输入
1 6
.#..#.
输出
1 1 1 6
说明
只有一行。最左和最右两块过道距离为 5,这是唯一的最大取法。
样例3
输入
4 4
#...
####
####
..##
输出
1 4 4 1
说明
(1,4)(1,4)(1,4) 与 (4,1)(4,1)(4,1) 距离为 6。若只拿「行加列」最小和最大的两格 (1,2)(1,2)(1,2) 与 (4,2)(4,2)(4,2),距离只有 3,不是最大。
思路
解题方法:逻辑分析
∣r1−r2∣+∣c1−c2∣分解之后,最大值求一下几种情况最大值- (r1+c1)−(r2+c2)
- (r2+c2)−(r1+c1)
- (r1−c1)−(r2−c2)
- (r2−c2)−(r1−c1)
- 按照上面公式我们只需要找
r + c最大和最小两个过道格, 对应1,2r - c最大和最小的两个过道格。对应3,4
- 最大值为
max(max(r + c) - min(r + c), max(r-c) - min(r -c))
python
python
import sys
class Point:
def __init__(self, r, c):
self.r = r
self.c = c
def solve(h, w, input_data):
maxSum = -sys.maxsize
minSum = sys.maxsize
maxDiff = -sys.maxsize
minDiff = sys.maxsize
maxSumPoint = None
minSumPoint = None
maxDiffPoint = None
minDiffPoint = None
# 一次只读取一行,因此不需要保存整个网格
for r in range(1, h + 1):
s = next(input_data)
for c in range(1, w + 1):
if s[c - 1] != '.':
continue
sum_val = r + c
diff = r - c
# 更新 r + c 最大值
if sum_val > maxSum:
maxSum = sum_val
maxSumPoint = Point(r, c)
# 更新 r + c 最小值
if sum_val < minSum:
minSum = sum_val
minSumPoint = Point(r, c)
# 更新 r - c 最大值
if diff > maxDiff:
maxDiff = diff
maxDiffPoint = Point(r, c)
# 更新 r - c 最小值
if diff < minDiff:
minDiff = diff
minDiffPoint = Point(r, c)
# r + c 方向的最大曼哈顿距离
d1 = maxSum - minSum
# r - c 方向的最大曼哈顿距离
d2 = maxDiff - minDiff
if d1 >= d2:
print(
minSumPoint.r, minSumPoint.c,
maxSumPoint.r, maxSumPoint.c
)
else:
print(
minDiffPoint.r, minDiffPoint.c,
maxDiffPoint.r, maxDiffPoint.c
)
def main():
input_data = iter(sys.stdin.read().split())
h = int(next(input_data))
w = int(next(input_data))
solve(h, w, input_data)
if __name__ == "__main__":
main()
C++
python
#include <bits/stdc++.h>
using namespace std;
struct Point {
int r, c;
};
void solve(int h, int w) {
int maxSum = INT_MIN;
int minSum = INT_MAX;
int maxDiff = INT_MIN;
int minDiff = INT_MAX;
Point maxSumPoint, minSumPoint;
Point maxDiffPoint, minDiffPoint;
// 一次只读取一行,因此不需要保存整个网格
for (int r = 1; r <= h; r++) {
string s;
cin >> s;
for (int c = 1; c <= w; c++) {
if (s[c - 1] != '.') {
continue;
}
int sum = r + c;
int diff = r - c;
// 更新 r + c 最大值
if (sum > maxSum) {
maxSum = sum;
maxSumPoint = {r, c};
}
// 更新 r + c 最小值
if (sum < minSum) {
minSum = sum;
minSumPoint = {r, c};
}
// 更新 r - c 最大值
if (diff > maxDiff) {
maxDiff = diff;
maxDiffPoint = {r, c};
}
// 更新 r - c 最小值
if (diff < minDiff) {
minDiff = diff;
minDiffPoint = {r, c};
}
}
}
// r + c 方向的最大曼哈顿距离
int d1 = maxSum - minSum;
// r - c 方向的最大曼哈顿距离
int d2 = maxDiff - minDiff;
if (d1 >= d2) {
cout << minSumPoint.r << ' ' << minSumPoint.c << ' '
<< maxSumPoint.r << ' ' << maxSumPoint.c << '\n';
} else {
cout << minDiffPoint.r << ' ' << minDiffPoint.c << ' '
<< maxDiffPoint.r << ' ' << maxDiffPoint.c << '\n';
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int h, w;
cin >> h >> w;
solve(h, w);
return 0;
}
Java
java
import java.io.*;
import java.util.*;
public class Main {
static class Point {
int r, c;
Point(int r, int c) {
this.r = r;
this.c = c;
}
}
static void solve(int h, int w, Scanner sc) {
int maxSum = Integer.MIN_VALUE;
int minSum = Integer.MAX_VALUE;
int maxDiff = Integer.MIN_VALUE;
int minDiff = Integer.MAX_VALUE;
Point maxSumPoint = null;
Point minSumPoint = null;
Point maxDiffPoint = null;
Point minDiffPoint = null;
// 一次只读取一行,因此不需要保存整个网格
for (int r = 1; r <= h; r++) {
String s = sc.next();
for (int c = 1; c <= w; c++) {
if (s.charAt(c - 1) != '.') {
continue;
}
int sum = r + c;
int diff = r - c;
// 更新 r + c 最大值
if (sum > maxSum) {
maxSum = sum;
maxSumPoint = new Point(r, c);
}
// 更新 r + c 最小值
if (sum < minSum) {
minSum = sum;
minSumPoint = new Point(r, c);
}
// 更新 r - c 最大值
if (diff > maxDiff) {
maxDiff = diff;
maxDiffPoint = new Point(r, c);
}
// 更新 r - c 最小值
if (diff < minDiff) {
minDiff = diff;
minDiffPoint = new Point(r, c);
}
}
}
// r + c 方向的最大曼哈顿距离
int d1 = maxSum - minSum;
// r - c 方向的最大曼哈顿距离
int d2 = maxDiff - minDiff;
if (d1 >= d2) {
System.out.println(
minSumPoint.r + " " + minSumPoint.c + " " +
maxSumPoint.r + " " + maxSumPoint.c
);
} else {
System.out.println(
minDiffPoint.r + " " + minDiffPoint.c + " " +
maxDiffPoint.r + " " + maxDiffPoint.c
);
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int h = sc.nextInt();
int w = sc.nextInt();
solve(h, w, sc);
}
}
javascript
js
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
const lines = [];
rl.on('line', line => {
lines.push(line.trim());
});
rl.on('close', () => {
let index = 0;
const [h, w] = lines[index++].split(/\s+/).map(Number);
solve(h, w);
});
class Point {
constructor(r, c) {
this.r = r;
this.c = c;
}
}
function solve(h, w) {
let maxSum = -Infinity;
let minSum = Infinity;
let maxDiff = -Infinity;
let minDiff = Infinity;
let maxSumPoint = null;
let minSumPoint = null;
let maxDiffPoint = null;
let minDiffPoint = null;
// 一次只读取一行,因此不需要保存整个网格
for (let r = 1; r <= h; r++) {
const s = lines[r];
for (let c = 1; c <= w; c++) {
if (s[c - 1] !== '.') {
continue;
}
const sum = r + c;
const diff = r - c;
// 更新 r + c 最大值
if (sum > maxSum) {
maxSum = sum;
maxSumPoint = new Point(r, c);
}
// 更新 r + c 最小值
if (sum < minSum) {
minSum = sum;
minSumPoint = new Point(r, c);
}
// 更新 r - c 最大值
if (diff > maxDiff) {
maxDiff = diff;
maxDiffPoint = new Point(r, c);
}
// 更新 r - c 最小值
if (diff < minDiff) {
minDiff = diff;
minDiffPoint = new Point(r, c);
}
}
}
// r + c 方向的最大曼哈顿距离
const d1 = maxSum - minSum;
// r - c 方向的最大曼哈顿距离
const d2 = maxDiff - minDiff;
if (d1 >= d2) {
console.log(
minSumPoint.r + ' ' + minSumPoint.c + ' ' +
maxSumPoint.r + ' ' + maxSumPoint.c
);
} else {
console.log(
minDiffPoint.r + ' ' + minDiffPoint.c + ' ' +
maxDiffPoint.r + ' ' + maxDiffPoint.c
);
}
}
Go
go
package main
import (
"bufio"
"fmt"
"os"
)
func solve(h, w int, in *bufio.Reader) {
maxSum := -int(^uint(0)>>1) - 1
minSum := int(^uint(0) >> 1)
maxDiff := -int(^uint(0)>>1) - 1
minDiff := int(^uint(0) >> 1)
var maxSumR, maxSumC int
var minSumR, minSumC int
var maxDiffR, maxDiffC int
var minDiffR, minDiffC int
// 一次只读取一行,因此不需要保存整个网格
for r := 1; r <= h; r++ {
var s string
fmt.Fscan(in, &s)
for c := 1; c <= w; c++ {
if s[c-1] != '.' {
continue
}
sum := r + c
diff := r - c
// 更新 r + c 最大值
if sum > maxSum {
maxSum = sum
maxSumR = r
maxSumC = c
}
// 更新 r + c 最小值
if sum < minSum {
minSum = sum
minSumR = r
minSumC = c
}
// 更新 r - c 最大值
if diff > maxDiff {
maxDiff = diff
maxDiffR = r
maxDiffC = c
}
// 更新 r - c 最小值
if diff < minDiff {
minDiff = diff
minDiffR = r
minDiffC = c
}
}
}
// r + c 方向的最大曼哈顿距离
d1 := maxSum - minSum
// r - c 方向的最大曼哈顿距离
d2 := maxDiff - minDiff
out := bufio.NewWriter(os.Stdout)
defer out.Flush()
if d1 >= d2 {
fmt.Fprintln(out,
minSumR, minSumC,
maxSumR, maxSumC)
} else {
fmt.Fprintln(out,
minDiffR, minDiffC,
maxDiffR, maxDiffC)
}
}
func main() {
in := bufio.NewReader(os.Stdin)
var h, w int
fmt.Fscan(in, &h, &w)
solve(h, w, in)
}