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
  • 相关阅读:
    .net注册iis
    hdu 1081To The Max
    hdu 1312Red and Black
    hdu 1016Prime Ring Problem
    hdu 1159Common Subsequence
    hdu 1372Knight Moves
    hdu 1686Oulipo
    hdu 1241Oil Deposits
    hdu 1171Big Event in HDU
    hdu 4006The kth great number
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5115791.html
Copyright © 2011-2022 走看看