LFYZ-OJ ID: 1017 士兵站队问题

分析

该题和“输油管道问题”类似,只不过由一维问题编程了二维问题。可以将总步数分解为移动到水平线y位置的总步数ysteps和移动到序列x, x+1, x+2, ... , x+n-1位置的总步数xsteps

  • ysteps的最小值容易计算,将所有士兵的纵坐标ypos[]排序后找出中位数,然后计算abs(xpos[1...n]-zws)即可。
  • xsteps的作如下分析:

共n个士兵,他们相应的X轴坐标为:x0, x1, x2 ... xn-1
设,士兵需要移动到的最终位置的x轴坐标值为:x, x+1, x+2, ..., x+(n-1)
则所求最优步数S=|x0-x|+|x1-(x+1)|+|x2-(x+2)|+...+|xn-1-(x+(n-1))|
经过变形S=|x0-x|+|(x1-1)-x|+|(x2-2)-x|+ ... +|(xn-1-(n-1))-x|
发现没有,问题已经变了,我们现在是在求序列x0, x1-1, x1-2, x1-3, ... xn-1-(n-1)与x绝对值之差的累加和的最小值。这和y方向上的计算是一样的了!因此还是采用取中位数的办法求得x值,最后算出最优解。

  • 整理一下, 思路如下:
    1. 排序y序列ypos
    2. 求出y坐标序列ypos的中位数y_zws
    3. 计算y方向上的最小步数ysteps
    4. 排序x序列xpos
    5. 计算新序列xpos[i]-=(i-1),如xpos[5]-=4
    6. 排序x序列xpos
    7. 计算x方向上的最小步数xsteps
    8. 输出xsteps+ysteps

代码示例

#include<iostream>
#include<cmath>
using namespace std;
int xpos[10001];							//士兵x坐标集合 
int ypos[10001];							//士兵y坐标集合
void qsort(int Data[], int low, int high){  //快速排序
  int i=low, j=high, m=Data[(low+high)/2];
  while(i<=j){
    while(Data[i]<m)    i++;
    while(Data[j]>m)    j--;
    if(i<=j){
      int t=Data[i];
      Data[i]=Data[j];
      Data[j]=t;
      i++, j--;
    }
  }
  if(j>low)   qsort(Data, low, j);	        //对右部分排序
  if(i<high)  qsort(Data, i, high); 	    //对左部分排序
}
int main(){
	int n, steps=0;
	scanf("%d", &n);
	for(int i=1; i<=n; i++)	scanf("%d%d", &xpos[i], &ypos[i]);
	qsort(ypos, 1, n);                      //排序ypos序列
	qsort(xpos, 1, n);                      //排序xpos序列
	for(int i=1; i<=n; i++)	xpos[i]-=(i-1); //生成新的xpos序列
	qsort(xpos, 1, n);                      //重排xpos序列
	for(int i=1; i<=n; i++)                 //计算步数
		steps+=(abs(xpos[i]-xpos[n/2+1])+abs(ypos[i]-ypos[n/2+1]));
	printf("%d", steps);
	return 0;
}
posted @ 2017-05-10 18:32  LFYZOI题解  阅读(515)  评论(0编辑  收藏  举报