士兵排队问题

本文探讨了士兵站队问题的最优解法,通过分析士兵的Y轴和X轴坐标,采用取中位数的方法求得最终位置,进而计算最小移动步数。解决了士兵移动的效率问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 士兵有多种移动方式
通过适当的移动顺序和移动路线可以使得同一时刻不会有两名士兵站在同一点
二 题目要求最佳移动方式(即求移动的最少步数)
题目要求转化为求士兵站立的“最终位置”,即如何取“最终位置”使得士兵移动的步数最少(最优)
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");
}        


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值