给定N个坐标点,每个点代表一个士兵。现要让每个士兵都在一条水平线上,并且相邻。士兵每次可以上下左右移动一次。求达到目的的最少移动次数。任意时刻不能有两个士兵重叠。
此题可以分两步做:第一步求出所有点到水平线上的次数之和,再求出在水平线上重新排列需要的次数。
第一步很明显可以现找出要在哪条水平线上,找出一条水平线使得坐标点到线上距离之和最短,也就是要求Y轴坐标排序后的中位数那条。
第二步抽象一点,要发现所有士兵按X轴排序后的相对位置和排序前的相对位置是一样的,因为这样才能保证移动次数最少。可能你会担心有士兵在X轴上重叠了,但经过下面的步骤可以消除这一点。也就是不影响最后的答案。
假设最后开始坐标是a,也就是v[0]=a,v[1]=a+1......,所以就是要让
v[0]=>a
v[1]=>a+1
v[2]=>a+2
……
转换一下:
v[0]=>a
v[1]-1=>a
v[2]-2=>a
……
很惊奇的发现就是让v[0],v[1]-1,v[2]-2……的点到同一点a的距离,那么就很第一步的做法一样了,取中位数。
代码如下:
#include <iostream> #include <stdio.h> #include <string.h> #include <vector> #include <algorithm> using namespace std; typedef long long ll; int n,ans,line[20005]; struct node { int a,b; }v[10003]; bool cmpy(node a,node ab) { if(a.b!=ab.b) return a.b<ab.b; return a.a<ab.a; } bool cmpx(node a,node ab) { if(a.a!=ab.a) return a.a<ab.a; return a.b<ab.b; } int main(int argc, char **argv) { cin>>n; for(int i=0;i<n;++i) cin>>v[i].a>>v[i].b; sort(v,v+n,cmpy); int my=v[n/2].b; for(int i=0;i<n;++i){ ans+=abs(my-v[i].b); } sort(v,v+n,cmpx); for(int i=0;i<n;++i) v[i].a-=i; sort(v,v+n,cmpx); int mx=v[n/2].a; for(int i=0;i<n;++i) ans+=abs(mx-v[i].a); cout<<ans<<endl; return 0; }
浙公网安备 33010602011771号