zoukankan      html  css  js  c++  java
  • POJ 1723 SOLDIERS (中位数)

    题目大意:

    平面上有N(N<=10000)个点,求这些点变成一条水平线的最小移动步数。

    算法讨论:

    表示自己太弱弱了,打算从今天开始提高一下智商。

    我们考虑,既然是要成一条水平线,那么这条直线的y坐标肯定是所有y的中位数了。这是不用置疑的。所以我们只要求出中位数,然后对y坐标的距离差求下和就可以了。

    对于x坐标,我们这样考虑,既然题目要求是最小步数,那么也就是说,这些博士兵在水平位置上的相对位置不变,换个意思说就是 原来三个士兵的x坐标是 -1 5 6,那么在他们移动之后,假设移动成一条直线之后,起点是原来-1的那个士兵,现在的坐标是9,那么他们之间的相对位置就是9 10 11...

    那么,这样来说,我们就可以这样想:假设最后水平线的起点是a,根据上面的理论可以得到  x'[0] = a, x'[1] = a+1, x'[2] = a+2...

    移项,可以得到x[0] - 0 = a, x[1] - 1 = a, x[2] - 2 = a.....

    所以我们把每个x[i] 都减去i,然后再从小到大排序,这样就保证在相对位置不变的情况下成一条水平线。然后把距离差求和就可以了。

    还值得一提的,下标从0开始的时候,mid = n / 2, 从1 开始的时候, mid = n / 2 + 1。。。。也是诡异。

    Codes:

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdlib>
     5 #include <algorithm>
     6 using namespace std;
     7 const int N = 10000 + 5;
     8 typedef long long ll;
     9 
    10 int n, mid;
    11 int x[N], y[N];
    12 ll step_x = 0, step_y = 0;
    13 
    14 int main(){
    15     while(~scanf("%d", &n)){
    16         mid = n / 2 + 1;
    17         step_x = step_y = 0;
    18         for(int i = 1; i <= n; ++ i)
    19             scanf("%d%d", &x[i], &y[i]);
    20         
    21         sort(y + 1, y + n + 1);
    22         for(int i = 1; i <= n; ++ i) step_y += abs(y[i] - y[mid]);
    23         sort(x + 1, x + n + 1);
    24         for(int i = 1; i <= n; ++ i) x[i] -= i;
    25         sort(x + 1, x + n + 1);
    26         for(int i = 1; i <= n; ++ i) step_x += abs(x[i] - x[mid]);
    27          
    28         printf("%lld
    ", (ll) step_x + step_y);
    29     }
    30     
    31     return 0;
    32 }
    POJ 1723
  • 相关阅读:
    luogu 1169 棋盘制作(单调栈/悬线)
    poj 2769 感觉♂良好 (单调栈)
    hdu 5033 buiding(单调栈)
    hdu1506 直方图中最大的矩形 单调栈入门
    有线电视网(树形dp)
    洛谷P1220 关路灯(区间dp)
    【题解】NOI2009二叉查找树 + NOIP2003加分二叉树
    【题解】AHOI2009中国象棋
    【算法】Matrix
    【题解】WC2008游览计划
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5115791.html
Copyright © 2011-2022 走看看