-
描述
-
一个街区有很多住户,街区的街道只能为东西、南北两种方向。
住户只可以沿着街道行走。
各个街道之间的间隔相等。
用(x,y)来表示住户坐在的街区。
例如(4,20),表示用户在东西方向第4个街道,南北方向第20个街道。
现在要建一个邮局,使得各个住户到邮局的距离之和最少。
求现在这个邮局应该建在那个地方使得所有住户距离之和最小;
-
输入
-
第一行一个整数n<20,表示有n组测试数据,下面是n组数据;
每组第一行一个整数m<20,表示本组有m个住户,下面的m行每行有两个整数0<x,y<100,表示某个用户所在街区的坐标。
m行后是新一组的数据;
输出
- 每组数据输出到邮局最小的距离和,回车结束; 样例输入
-
2 3 1 1 2 1 1 2 5 2 9 5 20 11 9 1 1 1 20
样例输出
-
2
44
-
-
分析:因为街区的街道只能为东西、南北两种方向,所以一个点到另一个点的距离即为:横坐标之间的差值加上纵坐标之间的差值
-
以横坐标为例,很显然的到各个横坐标距离之和最近的点即是各横坐标的中位数
-
因此有了以下代码:
-
这也是我最初的做法,但很显然,这样的方法是笨拙、没有技巧的。而看了许多文章,有一种共同的优化方案:#include<stdio.h> #include<stdlib.h> #include<math.h> void maopaoShort(int numbers[],int length) { int temp; for (int i = 0; i < length; i++) { for (int j = 0; j < length-1-i; j++) { if (numbers[j]>numbers[j + 1]) { temp = numbers[j + 1]; numbers[j + 1] = numbers[j]; numbers[j] = temp; } } } } int main() { int n; int m; int x[100]; int y[100]; int midX; int midY; int sum = 0; scanf("%d",&n); while (n--) { scanf("%d",&m); for (int i = 0; i < m;i++) { scanf("%d %d",&x[i],&y[i]); } maopaoShort(x,m); maopaoShort(y,m); if (m%2!=0) { midX = x[m / 2]; midY = y[m / 2]; } else { midX = (x[m / 2]+ x[(m / 2) - 1]) / 2; midY = (y[m / 2] + y[m / 2 - 1]) / 2; } for (int i = 0; i < m; i++) { sum += abs(x[i] - midX) + abs(y[i] - midY); //可优化点 } printf("%d\n",sum); sum = 0; } }
-
它将
替换为了for (int i = 0; i < m; i++) { sum += abs(x[i] - midX) + abs(y[i] - midY); //可优化点 }
for (int i = 0; i < m/2; i++) {
sum += x[m - 1 - i] - x[i] + y[m - 1 - i] - y[i];
}
-
一是不用再调用库函数abs,二是运算量减少了很多,包括求和的,以及求中位数的。
-
但这个优化是怎么来的呢?刚开始我也对这个问题很是困惑不解,为什么通过简单的相见相加就完成了较为复杂的逻辑呢?
-
于是我拿起了笔书写下了运算过程
-
-
结果是一个很简单,没什么技巧的过程,但没深厚的数学功底,一下子怕也看不出来。
-
-
最终代码
-
#include<stdio.h> #include<stdlib.h> void maopaoShort(int numbers[],int length) { int temp; for (int i = 0; i < length; i++) { for (int j = 0; j < length-1-i; j++) { if (numbers[j]>numbers[j + 1]) { temp = numbers[j + 1]; numbers[j + 1] = numbers[j]; numbers[j] = temp; } } } } int main() { int n; int m; int x[100]; int y[100]; int midX; int midY; int sum = 0; scanf("%d",&n); while (n--) { scanf("%d",&m); for (int i = 0; i < m;i++) { scanf("%d %d",&x[i],&y[i]); } maopaoShort(x,m); maopaoShort(y,m); for (int i = 0; i < m/2; i++) { sum += x[m - 1 - i] - x[i] + y[m - 1 - i] - y[i]; } printf("%d\n",sum); sum = 0; } }