士兵排队
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