Vijos P2773 士兵站队

来源:互联网 发布:java 画流程图 编辑:程序博客网 时间:2024/04/28 11:43
【问题描述】
 
  在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点由整数坐标(x,y)表示。士兵每一步可沿着网格边上、下、左、右移动到相邻格子,但在同一时刻一个网格上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何选择x,y的值,才能使士兵们以最少的总移动步数排成一列。
  请计算使所有士兵排成一行需要的最少移动步数。 
 
【输入格式】
 
  第1行是士兵总数n。接下来的n行是士兵的初始位置,每行两个整数x和y。
 
【输出格式】
 
  输出士兵排成一行需要的最少移动步数。
 
【输入样例】
 
5
1 2
2 2
1 3
3 -2
3 3
 
【输出样例】
 
8
 
【数据范围】
 

1<=n<=10000  -10000<=x,y<=10000


分析:

首先意识到xy轴方向上的移动不会互相干扰,于是开始分开考虑x轴y轴上士兵的移动。

对于士兵在y轴方向的移动,一眼就可以看出来是一个明显的中位数了。所以问题就来了。。。x轴呢?

对于士兵的站位情况进行讨论:如果有士兵站在一起,就是明显的直接散开就可以了;但是如果旁边有其他的士兵夹着呢?举几个例子就可以发现士兵交换相对位置的最短路程和不交换相对位置的最短路程实际上是一样的。如果士兵是分散开来站的呢?明显的,如果他们在移动过程中交换了相对位置,是不必不交换相对位置更优的。

于是得到结论:士兵最后是不交换他们的相对位置的(PS:如果横坐标一样就无所谓了啦~)

那么就有如下的推导了:

设最后排头兵的横坐标为x0,则对士兵的横坐标排序之后,有x1->x0,x2->x0+1,...,xn->x0+n-1;
ansx=|x1 - x0|+|x2-1 - x0|+...+|xn+1-n - x0|

ans=ansx+ansy

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<set>#include<map>#include<vector>#include<queue>#include<cctype>#include<ctime>#define INF 1000000005using namespace std;const int maxn=10005;int N,X[maxn],Y[maxn],ans,A[maxn];int main(){freopen("test.in","r",stdin);freopen("test.out","w",stdout);scanf("%d",&N);for(int i=1;i<=N;i++){scanf("%d",&X[i]);scanf("%d",&Y[i]);}sort(Y+1,Y+N+1);int mid=Y[(N+1)/2];for(int i=1;i<=N;i++) ans+=abs(Y[i]-mid);sort(X+1,X+N+1);for(int i=1;i<=N;i++) A[i]=X[i]+1-i;sort(A+1,A+N+1);mid=A[(N+1)/2];for(int i=1;i<=N;i++) ans+=abs(A[i]-mid);printf("%d",ans);return 0;}


又是中位数!!!(这个问题不懂的小伙伴可以去自己证明一下,只要不是靠脑补应该都可以算出来)


原创粉丝点击