输油管道做题报告

某石油公司计划建造一条由东向西的主输油管道。该管要穿过一个有n口油井的油田。每口油田都有一条输油管道沿最短路径(或南或北)与主管相连。如果给定n口油井的位置,即它们的X坐标(东西向)和y坐标(南北向),应如何确定主管的最优位置,即使个油井到主管道之间的输油管道长度总和最小的位置,证明可在线性时间内确定主管道的最优给定n口油井的位置,编程计算各油井到主管道之间的输油管道长度总和的最小值

这道题首先可以看出跟x坐标没关系,然后我为了找最小值本来还想二分。其实正解是排序后y坐标直接取中位数作为主管道的位置即可

中位数

中位数的性质

给定一个数列,中位数有这样的性质 :所有数与中位数的绝对差之和最小

中位数性质的简单证明

首先,给定一个从小到大的数列$x_1$,$x_2$,……,$x_n$,设$x$是从$x_1$到$x_n$与其绝对差之和最小的数,则显然$x$位于$x_1$与$x_n$之间。那么,由于$x_1,x_n$与它们之间的任意一点的距离之和都相等,且都等于$x_n-x_1$,因此接下来可以不考虑$x_1$与$x_n$,而考虑剩下的从$x_2$到$x_n-_1$的数,同样显然有$x$必然位于$x_2$和$x_n-_1$之间,依次类推,最后得出的结论是x就是该数列中间的那个数,或者是中间的那两个数之一,而这个数就是中位数。

结论:数列的中位数就是该数列各个数与其绝对差之和最小的数。

$code$

#include <cstdio>
#include <algorithm>

inline void read(int &x)
{
    x=0;char ch=0;bool sign=false;
    while(ch<'0' || ch>'9')
    {
        sign|=(ch== '-');
        ch=getchar();
    }
    while(! (ch<'0' || ch>'9'))
    {
        x=x*10+(ch^48);
        ch=getchar();
    }
    x=sign? -x : x;
}

inline void print(long long x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)print(x/10);
    putchar(x%10+'0');
}

struct node
{
    int x,y;
    bool operator < (const node & rhs)const{
        return y<rhs.y;
    }
}a[110000];
int n;
int sum;
int ans;
inline int abs(int x)
{
    return x>0?x:-x;
}

int main()
{
    freopen("pipe.in","r",stdin);
    freopen("pipe.out","w",stdout);
    read(n);
    for(int i=1; i<=n; i++)
    {
        read(a[i].x),read(a[i].y);
    }
    std::sort(a+1,a+n+1);
    int temp=a[(n+1)/2].y;
    int ans=0;
    for(int i=1; i<(n+1)/2; i++)
    {
        ans+=abs(temp-a[i].y);
    }
    for(int i=(n+1)/2+1; i<=n; i++)
    {
        ans+=abs(temp-a[i].y);
    }
    print(ans);
}
posted @ 2018-12-10 23:23  加固文明幻景  阅读(48)  评论(0编辑  收藏  举报  来源