description
的棋盘式网状布局。这个棋盘中的每一个横行和纵行均为一条道路,在某些道路交叉点上具有一栋建筑。每一栋建筑可以由一个二维坐标 表示,表示这一栋建筑处于第 横行、第 纵行的两条道路的交叉点上。
现在,良乡要在某一个道路交叉点上(可能已经有建筑)新建立一个供暖站。新的供暖站将修建供热管道到已有的每一栋建筑。为了方便维修,供暖管道只能直接修建在道路之下。为了最小化成本,良乡管理处想要让要修建的管道的总长度最小。
假定这个道路“棋盘”是单位均匀的(也就是每一个交叉点到相邻的四个交叉点之间的距离均为1)。现在良乡管理处想要知道,他们最少需要修建多长的管道。
输入描述
输入文件第一行为一个整数 ,表示已有建筑的数量。
接下来的 行,每行包含两个以空格分隔的整数 和 ,分别表示每一栋建筑的坐标。
输出描述
输出一行一个整数表示需要新修建的管道的最短长度。
样例说明
对于第二组测试用例,供暖站直接建在 (50, 50) 处即可。
code
- 管道要通到每一栋建筑,那么供暖站建在现有建筑上一定是最短的(但不是说一定要建在现有建筑上才能最短,可以建在路径上),建在任何一个建筑下都不会影响管道长度,因为只需要输出最短长度,那么直接利用现有建筑坐标作为切入点
- 题目说管道只建在道路下面,且是单位距离,那就相当于把x和y分割开来了,两个建筑物之间的距离
dis = |x'-x|+|y'-y|
; - 可以各自研究
- 只需要进行排序,然后选择中间的那一个建筑物作为供暖站即可
- 排序我使用的是归并排序,如果不是很理解我的代码可以看看这个先 https://editor.csdn.net/md/?articleId=121308155
- 特别注意
1). 管道不可以共用,即使两个建筑物在同一条直线上
2). 相同的x或者y也要累加,不能只算一次
代码如下
/******************************************
* @Author : 鱼香肉丝没有鱼
* @Date : 2021-10-28 11:06:13
* @LastEditors : 鱼香肉丝没有鱼
* @LastEditTime : 2021-11-15 15:40:37
******************************************/
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
//此题中未使用
template <typename T>
void PrintArray(T arr[], int n)
{
int i;
for(i = 0; i < n; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
//使用模板,不止适用于整型数组,浮点型等其他也可以
template <typename T> //在这了typename和class没有区别
void MergeSort(T arr[], int n)
{
int step, left_min, left_max, right_min, right_max; //步长,两个子串的左右边界,区间是左开右闭
int cnt; // temp数组的下标
T* temp = new T[n]; //辅助数组,和原数组一样长
for(step = 1; step < n; step += step) { // step是步长,也就是区间长度
for(left_min = 0; left_min < n - step; left_min = right_max) {
right_min = left_max = left_min + step; //右边界等于左边界+区间长度
right_max = right_min + step;
if(right_max > n)
right_max = n; //不能超出数组原本的长度嘛
cnt = 0;
while(left_min < left_max && right_min < right_max) { //只要有一边遍历完就退出
// 左右两边谁小取谁存入temp中,然后各自下标递增
if(arr[left_min] < arr[right_min])
temp[cnt++] = arr[left_min++];
else
temp[cnt++] = arr[right_min++];
}
/*上面的while循环如果退出那么一定是左右两边其中一个子串遍历完了
但是另一个子串可能还有剩余元素没有遍历。假如右边剩,因为每次取的都是较小的值,
如果右边剩的话那就不用管了,本来就是应该放在右边的,只用考虑左边剩的情况
*/
while(left_min < left_max) //右边剩的话不会进入这个while循环
arr[--right_min] = arr[--left_max]; //把左边的剩下元素放在右边,注意这时候rightmin指向
// 的是rightmax的位置,使用前都要自减
while(cnt > 0)
arr[--right_min] = temp[--cnt]; // tmep中的元素是有序的,现在还原到arr中,注意下标是先自减
}
}
delete[] temp;
}
//累加管道长度
long long int GetDistance(int* arr, int n)
{
long long dis = 0;
int mid = 0;
mid = n / 2;
for(register int i = 0; i < n; i++) {
dis += fabs(arr[mid] - arr[i]);
}
return dis;
}
int main()
{
int n;
int* row = NULL; //存储行
int* line = NULL; //存储列
long long disX = 0;
long long disY = 0;
freopen("file in.txt", "r", stdin);
cin >> n;
row = new int[n];
line = new int[n];
for(register int i = 0; i < n; i++)
scanf("%d %d", &row[i], &line[i]);
MergeSort(row, n); //归并排序
MergeSort(line, n);
disX = GetDistance(row, n);
disY = GetDistance(line, n);
printf("%lld\n", disX + disY);
delete[] row;
delete[] line;
return 0;
}
summary
- 注意一点,供暖站应该修在中间那个建筑物上,而不是建在中心距离上,是不一样的,可以看一下下面这个代码和上面程序在mid的处理上有什么不一样
long long int GetDistance(int* arr, int n)
{
long long dis = 0;
long long int mid = 0;
mid = (arr[0]+arr[n-1]) / 2;
for(register int i = 0; i < n; i++) {
dis += fabs(mid - arr[i]);
}
return dis;
}
- 遇到了一个关于printf不明确的魔幻报错,整理在这了 vscode 提示printf不明确