一 士兵有多种移动方式
通过适当的移动顺序和移动路线可以使得同一时刻不会有两名士兵站在同一点
二 题目要求最佳移动方式(即求移动的最少步数)
题目要求转化为求士兵站立的“最终位置”,即如何取“最终位置”使得士兵移动的步数最少(最优)
Y轴方向上的考虑
设目标坐标为M,即n个士兵最终需要移动到的Y轴的坐标值为M
n个士兵的Y轴坐标分别为:
Y0,Y1,Y2 …… …… Yn-1
则最优步数S=|Y0-M|+|Y1-M|+|Y2-M|+ …… …… +|Yn-1-M|
结论:M取中间点的值使得S为最少(最优)
证明:……
从最上和最下的两个士兵开始递推……
最优位置
最优位置
归结到最后,处于中间位置的士兵的Y轴坐标值就是“最终位置”的Y轴坐标
可能有两种情况
士兵总数为双数情况:取中间两点间的任意一个位置
士兵总数为单数情况:取中间点的所在位置
解决办法:对所有的Y轴坐标进行排序(O(nlogn))或者进行线性时间选择(O(n))
然后取“中间”点的Y轴坐标值作为最佳位置M的值
最后通过公式求出Y轴方向上移动的最优步数
X轴方向上的考虑
首先需要对所有士兵的X轴坐标值进行排序
然后,按从左至右的顺序依次移动到每个士兵所对应的“最终位置”(最优),所移动的步数总和就是X轴方向上需要移动的步数
例,最左的士兵移动到“最终位置”的最左那位,第二个士兵移动到“最终位置”的第二位
则总的步数为:士兵一移动步数+士兵二移动步数+ …… +士兵n移动步数
如何确定X轴方向上的最佳的“最终位置”?
共n个士兵
他们相应的X轴坐标为:X0,X1,X2 …… …… Xn-1
设,士兵需要移动到的“最终位置”的X轴坐标值为:k,k+1,k+2 …… …… k+(n-1)
则所求最优步数S=|X0-k|+|X1- (k+1) |+|X2-(k+2)|+ …… +|Xn-1-(k+(n-1))|
经过变形S=|X0-k|+|(X1-1)-k|+|(X2-2)-k|+ …… …… +|(Xn-1-(n-1))-k|
注意到公式的形式与Y轴方向上的考虑一样,同样是n个已知数分别减去一个待定数后取绝对值,然后求和
通过适当的移动顺序和移动路线可以使得同一时刻不会有两名士兵站在同一点
二 题目要求最佳移动方式(即求移动的最少步数)
题目要求转化为求士兵站立的“最终位置”,即如何取“最终位置”使得士兵移动的步数最少(最优)
Y轴方向上的考虑
设目标坐标为M,即n个士兵最终需要移动到的Y轴的坐标值为M
n个士兵的Y轴坐标分别为:
Y0,Y1,Y2 …… …… Yn-1
则最优步数S=|Y0-M|+|Y1-M|+|Y2-M|+ …… …… +|Yn-1-M|
结论:M取中间点的值使得S为最少(最优)
证明:……
从最上和最下的两个士兵开始递推……
最优位置
最优位置
归结到最后,处于中间位置的士兵的Y轴坐标值就是“最终位置”的Y轴坐标
可能有两种情况
士兵总数为双数情况:取中间两点间的任意一个位置
士兵总数为单数情况:取中间点的所在位置
解决办法:对所有的Y轴坐标进行排序(O(nlogn))或者进行线性时间选择(O(n))
然后取“中间”点的Y轴坐标值作为最佳位置M的值
最后通过公式求出Y轴方向上移动的最优步数
X轴方向上的考虑
首先需要对所有士兵的X轴坐标值进行排序
然后,按从左至右的顺序依次移动到每个士兵所对应的“最终位置”(最优),所移动的步数总和就是X轴方向上需要移动的步数
例,最左的士兵移动到“最终位置”的最左那位,第二个士兵移动到“最终位置”的第二位
则总的步数为:士兵一移动步数+士兵二移动步数+ …… +士兵n移动步数
如何确定X轴方向上的最佳的“最终位置”?
共n个士兵
他们相应的X轴坐标为:X0,X1,X2 …… …… Xn-1
设,士兵需要移动到的“最终位置”的X轴坐标值为:k,k+1,k+2 …… …… k+(n-1)
则所求最优步数S=|X0-k|+|X1- (k+1) |+|X2-(k+2)|+ …… +|Xn-1-(k+(n-1))|
经过变形S=|X0-k|+|(X1-1)-k|+|(X2-2)-k|+ …… …… +|(Xn-1-(n-1))-k|
注意到公式的形式与Y轴方向上的考虑一样,同样是n个已知数分别减去一个待定数后取绝对值,然后求和
因此还是采用取中位数的办法求得k值,最后算出最优解
//士兵站队问题
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
int partition(int *a,int low,int high){
int key = a[low];
while(low<high){
while(low < high&&a[high] >= key)high--;
a[low] = a[high];
while(low<high&&a[low] <= key)low++;
a[high]=a[low];
}
a[low]=key;
return low;
}
int RandomizedPartition(int *a,int low,int high){
srand((unsigned int)time(NULL));
int i = rand()%(high-low+1)+low;
int temp;
temp = a[i];
a[i] = a[low];
a[low] = temp;
return partition(a,low,high);
}
int RandomizedSelect(int *a,int p,int r,int k){
if(p == r) return a[p];
int i=RandomizedPartition(a,p,r);
int j=i-p+1;
if(j==k) return a[i];
else
if(j > k) return RandomizedSelect(a,p,i-1,k);
else return RandomizedSelect(a,i+1,r,k-j);
}
void Qsort(int *a,int low,int high){
int key;
if(low<high){
key = RandomizedPartition(a,low,high);
Qsort(a,low,key-1);
Qsort(a,key+1,high);
}
}
int main(){
int x[10000],y[10000],n,xkey,ykey,x1[10000],sum;
while(cin>>n){
sum = 0;
for(int i =0;i < n;i ++)
cin>>x[i]>>y[i];
Qsort(x,0,n-1);
for(int i = 0;i < n;i++)
x1[i] = x[i]-i;
ykey=RandomizedSelect(y,0,n-1,(n+1)/2);
xkey=RandomizedSelect(x1,0,n-1,(n+1)/2);
for(int i = 0;i < n;i ++)
{
sum += abs(y[i]-ykey);
sum += abs(x1[i]-xkey);
}
cout<<"sum:"<<sum<<endl;
}
system("pause");
}