士兵排队

NOIP模拟题,很简单,但是用了一个有意思的思想所以决定写个题解

原题:

在Gridland国家,有N个处于不同位置的士兵。该国上的地方都用两个坐标(X,Y)来表示。士兵能进行一次移动,每个士兵都可向上、向下、向左、或向右移动一个单位长,这样他就能把自己的X或Y改变1或-1。
士兵们想进入一个水平线,彼此靠近,这样他们的最后位置就是(X,Y)、(X+1,Y),…,(X+N,Y))。水平线上的士兵的最后顺序以及整数X和Y,都是任意的。
现在目标是求如此配置士兵的最少移动数。
两个或两个以上的士兵在同一时间不处于同一位置。

1 <= N <=10000

首先一个小学级定理:多个数向一个数靠拢,如果每个数移动相同距离的花费相同,则最优解是中位数

y求中位数即可,x怎么办呐

由于最后x的格式固定为公差为1的等差数列,所以可以给x排完序后把x[i]-i,然后就把x的问题转化为多个数向中位数靠拢,然后就可以解决辣

想题要注重特殊性而不是一般性

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 int read(){int z=0,mark=1;  char ch=getchar();
 9     while(ch<'0'||ch>'9'){if(ch=='-')mark=-1;  ch=getchar();}
10     while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0';  ch=getchar();}
11     return z*mark;
12 }
13 int n,x[11000],y[11000];
14 int main(){//freopen("ddd.in","r",stdin);
15     cin>>n;  int N=(n+1)>>1;
16     for(int i=1;i<=n;++i)  x[i]=read(),y[i]=read();
17     sort(y+1,y+n+1),sort(x+1,x+n+1);
18     for(int i=1;i<=n;++i)  x[i]-=i;
19     sort(x+1,x+n+1);
20     int bowl=0;
21     for(int i=1;i<=n;++i)  bowl+=abs(y[i]-y[N])+abs(x[i]-x[N]);
22     cout<<bowl<<endl;
23     return 0;
24 }
25 
26 
27     
View Code
原文地址:https://www.cnblogs.com/JSL2018/p/6405669.html