**

POJ 1723 士兵排队 C语言实现

**

**
原文
**
Description
N soldiers of the land Gridland are randomly scattered around the country.
A position in Gridland is given by a pair (x,y) of integer coordinates. Soldiers can move - in one move, one soldier can go one unit up, down, left or right (hence, he can change either his x or his y coordinate by 1 or -1).

The soldiers want to get into a horizontal line next to each other (so that their final positions are (x,y), (x+1,y), …, (x+N-1,y), for some x and y). Integers x and y, as well as the final order of soldiers along the horizontal line is arbitrary.

The goal is to minimise the total number of moves of all the soldiers that takes them into such configuration.

Two or more soldiers must never occupy the same position at the same time.

Input

The first line of the input contains the integer N, 1 <= N <= 10000, the number of soldiers.
The following N lines of the input contain initial positions of the soldiers : for each i, 1 <= i <= N, the (i+1)st line of the input file contains a pair of integers x[i] and y[i] separated by a single blank character, representing the coordinates of the ith soldier, -10000 <= x[i],y[i] <= 10000.

Output

The first and the only line of the output should contain the minimum total number of moves that takes the soldiers into a horizontal line next to each other.

Sample Input

5

1 2

2 2

1 3

3 -2

3 3

Sample Output

8

翻译
格格兰郡的N名士兵随机散落在全郡各地。

格格兰郡中的位置由一对(x,y)整数坐标表示。

士兵可以进行移动,每次移动,一名士兵可以向上,向下,向左或向右移动一个单位(因此,他的x或y坐标也将加1或减1)。

现在希望通过移动士兵,使得所有士兵彼此相邻的处于同一条水平线内,即所有士兵的y坐标相同并且x坐标相邻。

请你计算满足要求的情况下,所有士兵的总移动次数最少是多少。

需注意,两个或多个士兵不能占据同一个位置。
输入格式

第一行输入整数N,代表士兵的数量。

接下来的N行,每行输入两个整数x和y,分别代表一个士兵所在位置的x坐标和y坐标,第i行即为第i个士兵的坐标(x[i],y[i])。
输出格式

输出一个整数,代表所有士兵的总移动次数的最小值。
数据范围

1≤N≤10000
,
−10000≤x[i],y[i]≤10000

输入样例:

5
1 2
2 2
1 3
3 -2
3 3

输出样例:

8

解题思路
这道题主要考察中位数的应用

想要求走的最短路径,则需要知道怎样移动可以使步数最少

我们不妨将 x, y 坐标分开来看,想要移到同一条水平线上, 则需要最终的结果y 相同, x依次相邻, 且如果最左边的人的位置是x[a], 则最右边的人的坐标是x[a+N]

进一步,需要将此问题转化到数学模型。大家在中学阶段一定见过类似于求解 | x - 4 | + | 7 - x | + | 10 - x |最小值的问题,结果应该是当取到所以零点的中位数时,整体的值最小。如果不能直接记住结论则可以进行一个简单的归纳。即, 当只有一个的时候, 取该值,当有两个的时候取任意一个端点, 当有三个的时候则取中间的,有四个的时候则第二个或者第三个都可以。

再回到上文我们可以知道,最终结果的这条水平线的y 坐标应该是 这些 y 值得中位数。因为这个这个问题在 y 方向上的结果应该是 | ( y[i] - mid_y ) | + | ( y[i+1] - mid_y ) | +…+ | ( y[i+N-1] - mid_y ) |的最小值,所以代入中位数即可。

于是我们将 y 坐标进行排序,排序后中间的数即为中位数

y 方向上的步数比较好确定,那 x 轴方向上的呢?

我们不妨先看一下 x 轴上的步数求解的数学公式是什么样子的。我们假设这条线的第一个人的横坐标是A , 由于站成一排后横坐标是连续的, 所以接下来的横坐标依次是 A+1, A+2, … A+N-1;不妨将1 到 N 设置为循环变量 i, 则可以表示为 A+ i , 设每一点的横坐标为 x[ i ], 则对于每一点来说 移动的距离是 | A + i - x[ i ] |, i 从 0 到 N-1 这同样是一个绝对值排序问题,所以也应该我们也需要找到 x 的中位数, 我们为了便于排序, 设一个新的数组为 x[i] = x[i] - i; 经过这一步转换之后原问题则变成 | A - x[ i ] |

然后用一个循环进行相加即可

在处理 x 坐标时我们要知道横坐标的左右相对位置是没有变得,意思是原来相对在左的还是在左, 相对在右的还是在右,只有这样才会让 x 方向上的移动步数最少

总结一下就是现将 y 坐标排序,找到 y 方向上的中位数,将 y 方向上的步数求出来,然后是稍微麻烦一点的 x 轴, 先将x 轴进行一下排序, 现将 x 的坐标进行一下变换,然后再排序找到中位数, 进而累加求和

注意
这道题的空间与时间都不是无限的,可以看到这道题需要多次排序。所以我们就要尤其的注意时间复杂度。一般常用的冒泡排序等会出现超时现象。所以这道题可以使用 C++ STL 的 快速排序, 即 sort函数, 但是要想使用 C语言实现的话就需要找一个空间复杂度较低的方法,我这次采用的是 归并排序, (转载),这个是一个比较稳定且复杂度为 nlog2n的复杂度,用空间换时间,另外题中说-10000 <= x[i],y[i] <= 10000, 也要注意

下面是AC代码

#include <stdio.h>
#include <stdlib.h>  //包含 malloc 函数
#include <math.h> //包含 abs()函数
#define MAX_soldier 10000  //采用宏定义//声明归并排序函数原型
void merge(int arr[], int low, int mid, int high);
void merge_sort(int arr[], unsigned int first, unsigned int last);int main()
{int x[MAX_soldier], y[MAX_soldier], ; int i=0,j=0, total_soldier; // total_soldier 是题目中第一行需要输入的士兵的个数int mid_x, mid_y, step=0;  // mid_x, mid_y 分别表示 x , y 方向上的中位数//输入数据scanf("%d",&total_soldier);for(i=0;i<total_soldier;++i)scanf("%d %d",&x[i], &y[i]);//对 x , y 方向上的数据进行归并排序merge_sort(y,0,total_soldier-1);merge_sort(x,0,total_soldier-1);//求 y 方向上的中位数mid_y = y[(total_soldier+1)/2-1];//进行数组转换for(i=0;i<total_soldier;++i)x[i]-=i;//再次对 x 坐标排序merge_sort(x,0,total_soldier-1);//求x 方向中位数mid_x = x[(total_soldier+1)/2-1];//累加求和for(i=0; i<total_soldier; ++i)step+=abs(y[i] - mid_y) + abs(x[i] - mid_x);printf("%d",step);return 0;
} //定义归并排序函数void merge(int arr[], int low, int mid, int high)
{int i, k;int *tmp = (int *)malloc((high-low+1)*sizeof(int));//申请空间,使其大小为两个int left_low = low;int left_high = mid;int right_low = mid + 1;int right_high = high;for(k=0; left_low<=left_high && right_low<=right_high; k++){  // 比较两个指针所指向的元素if(arr[left_low]<=arr[right_low]){tmp[k] = arr[left_low++];}else{tmp[k] = arr[right_low++];}}if(left_low <= left_high){  //若第一个序列有剩余,直接复制出来粘到合并序列尾//memcpy(tmp+k, arr+left_low, (left_high-left_low+l)*sizeof(int));for(i=left_low;i<=left_high;i++)tmp[k++] = arr[i];}if(right_low <= right_high){//若第二个序列有剩余,直接复制出来粘到合并序列尾//memcpy(tmp+k, arr+right_low, (right_high-right_low+1)*sizeof(int));for(i=right_low; i<=right_high; i++)tmp[k++] = arr[i];}for(i=0; i<high-low+1; i++)arr[low+i] = tmp[i];free(tmp);return;
}
void merge_sort(int arr[], unsigned int first, unsigned int last)
{int mid = 0;if(first<last){mid = (first+last)/2; /* 注意防止溢出 *//*mid = first/2 + last/2;*///mid = (first & last) + ((first ^ last) >> 1);merge_sort(arr, first, mid);merge_sort(arr, mid+1,last);merge(arr,first,mid,last);}return;
}

POJ 1723 士兵排队 C语言实现相关推荐

  1. POJ 1723 Soldiers (中位数)

    $ POJ~1723~Soldiers $ (中位数) $ solution: $ 这道题说难也不算太难,但是当时自己想的很矛盾.所以还是列一篇题解. 这道题首先比较容易看出来的就是:行和列是两个分开 ...

  2. poj 1723 中位数

    最近在看一些中位数的东西,然后顺便也看了些题目.poj 1723不仅要求到水平位置的最短距离和,还要求水平都相邻的排成一排的最短距离和,即士兵都站成一列. 到y轴的距离好办,按y轴坐标排序,求中位数, ...

  3. G - SOLDIERS POJ - 1723 sort+数学

    G - SOLDIERS POJ - 1723 题解 好妙啊! 由于与路径没啥关系,走折线即可 先找出 y 的中位数,全部走到中位数的位置 对 x ,先排序,再构造一个 temp[i] = x[i] ...

  4. 用JDevelop编程软件运行代码:韩信点兵,韩信有一队兵,他想知道有多少人,便让士兵排队报数:

    作业:韩信有一队兵,他想知道有多少人,便让士兵排队报数: 按从 1 到 5 报,最末一个士兵报的数为 1 :按从 1 到 6 报, 最后一个士兵报的数为 5 ,按从 1 到 7 报,最末一个士兵 报的 ...

  5. 【POJ 1723 --- SOLDIERS】

    [POJ 1723 --- SOLDIERS] Description N soldiers of the land Gridland are randomly scattered around th ...

  6. POJ - 1723 Soldiers 士兵站队 排序+中位数

    [问题描述] 在一个划分成网格的操场上,n个士兵散乱地站在网格点上.网格点由整数最表(x,y)表示.士兵可以沿着网格边上.下.左.右移动一步,但在同一时刻一个网格上只能有一名士兵.按照军官的命令,士兵 ...

  7. 士兵排队(Java)

    在一个划分成网格的操场上,n个士兵散乱地站在网格点上.网格点用整数坐标(x,y)表示.士兵们可以沿网格边往上.下.左.右移动一步,但在同一时刻任一网格点上只能有一名士兵.按照军官的命令,士兵们要整齐地 ...

  8. POJ 1723(中位数+连续排列)

    题目大意:有N个士兵,每个士兵开始站的坐标是(x,y),现在使得将N个士兵站在同一个水平线(即所有士兵的y坐标相同)并且x坐标相邻,每个士兵每次可以移动一个位置(分别在x和y方向移动).求出最少的移动 ...

  9. 蓝桥杯 - 历届试题 小朋友排队 C语言实现

     历届试题 小朋友排队 时间限制:1.0s   内存限制:256.0MB 问题描述 n 个小朋友站成一排.现在要把他们按身高从低到高的顺序排列,但是每次只能交换位置相邻的两个小朋友. 每个小朋友都有一 ...

最新文章

  1. Java(CS)请求分流
  2. mysql降级导入_mysql 升级和降级
  3. 测试思想-测试总结 缺陷分析与统计浅析
  4. c语言字符型数据怎么输入输出,C语言基础之数据类型与输入/输出
  5. AndroidJava保留小数位数的几种写法
  6. python批量命名文件_用python实现批量重命名文件的代码
  7. 一些lightbox插件(弹出层)
  8. 谷歌Chrome紧急更新补丁0day漏洞
  9. 怎么删除feed php,怎样关闭或删除WordPress程序默认的RSS feed功能
  10. 022-互惠合作|离职员工的关系网
  11. 复古儿童卡通温馨手绘风格趣味MOGRT图形动画标题pr模板
  12. 平面设计师笔试题应答技巧|智测优聘总结
  13. 【微信小程序】wx:for的使用
  14. ARM® Cortex®-M内核单片机STM32家族介绍,覆盖STM32F、STM32H、STM32L全系列
  15. 非常有趣有特色的个人博客网站源码
  16. Jersey的配置(4)
  17. 2022-2023级北京大学光华管理学院MBA招生简章
  18. 我的世界服务器修改武器合成表,我的世界武器合成表大全 我的世界武器怎么合成...
  19. Mail.Ru邮箱注册教程
  20. CN_@物理层@信噪比@分贝单位@奈奎斯特定理@香农公式@常用编码方式(曼彻斯特编码/差分曼彻斯特编码)波形图

热门文章

  1. JavaScript学习过程
  2. pdf.js渲染不对 问题回顾
  3. Packet Tracer6.0静态路由,RIP,OSPF路由方案配置(1)
  4. StringBoot+jeefast 的图片上传
  5. 著名全球最大同性交友社区网站
  6. 广电在5G时代的发展和应对策略
  7. 中科大计算机招非全日制,中国科技大学有非全日制研究生招生吗?
  8. 广东计算机非全日制 学校2020,2020年广东省非全日制研究生学校及专业有那些?...
  9. 怎样阅读论文(台湾彭明辉)
  10. [ecshop 资料 ] 通联支付 wap 手机端 开发帮助中心 手机支付网关 帮助中心