输油管道做题报告
某石油公司计划建造一条由东向西的主输油管道。该管要穿过一个有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);
}