输油管道问题(线性时间解决)

输油管道问题

某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有 n口油井的油田。从每口油井都要有一条输油管道沿南北向最短路经与主管道相连。如果给定 n 口油井的地理位置,即它们的 x 坐标(东西向)和 y坐标(南北向),应如何确定主管道的最优位置,使得各油井到主管道之间的输油管道的长度总和最小?设计一个线性时间算法计算各油井到主管道之间的输油管道最小长度总和。

思考:
主输油管道应该是直的?
南北方向向移动直线使南北方向垂线距离之和最小?
那x坐标应该没什么用了吧?
输油管道问题(线性时间解决)_第1张图片看了一波其他人的博客思路,我大概题意理解正确,解决这个问题不难,关键是如何用线性时间来解决,联系所学章节主题—分治法进行解决。
我们可以证明:

如果油井y坐标个数为奇数,主管道y轴坐标肯定是等于某口油井的y坐标,且这口油井y坐标肯定为中位数。
如果油井y坐标个数为偶数,主管道y轴坐标肯定是是在某两口油井y坐标之间,且这两口油井的y坐标值位于所有y坐标的中间。
综上,主管道y坐标肯定为油井坐标值的中位数。

证明方法如下:
(反证法):
1.假设有三口油井,他们的y坐标各不相同,y1 2.假设有四口油井:y1 3.假设有五口油井:y1

要求中位数肯定是要先排序的啊!线性时间排序!
输油管道问题(线性时间解决)_第2张图片

#include 
#include 
#include 
#include 

using namespace std;
int Partition(int i,int j,int pivort,int A[])
{
     
    int l=i,r=j;
    while(1){
     
        while(A[r]>=pivort&&r>l)
            r--;
        if(l<r)
        {
     
            A[l]=A[r];
        }
        while(A[l]<pivort&&r>l)
            l++;
        if(l<r)
        {
     
            A[r]=A[l];
        }
        if(r<=l)
            break;
    }
    A[l]=pivort;
    return l;
}
int select(int i,int j,int A[],int l,int n)
{
     

    if((j-i+1)/5==0)
    {
     
        sort(A+i,A+j+1);
        return A[l];
    }
    for(int m=i;m<=(j-i+1)/5;m++)
    {
     
        sort(A+i-1+((m-1)*5+1),A+i-1+((m-1)*5+6));
        float a=(float(l)/float(j-i+1))*5.0;
        swap(A[m+i-1],A[(m-1)*5+i-1+int(a)+1]);
    }
    int x=select(i,(j-i+1)/5+i-1,A,(j-i+1)/10+i-1+1,n);
    if(x!=A[i])
    {
     
        for(int s=1;s<=n;s++)
        {
     
            if(x==A[s])
                swap(A[i],A[s]);
        }
    }
    int k=Partition(i,j,x,A);
    if(k==l)
        return x;
    else if (k>l)
        return select(i,k-1,A,l,n);
    else
        return select(k+1,j,A,l,n);
}
int main()
{
     
    int n;
    double dis=0.0;
    scanf("%d",&n);
    int X[n+1],Y[n+1];
    for(int i=1;i<=n;i++)
    {
     
        scanf("%d %d",&X[i],&Y[i]);
    }
    int mid=select(1,n,Y,n/2+1,n);
    cout<<"中位数"<<mid<<endl;
    for(int i;i<=n;i++)
    {
     
        dis =dis+sqrt((Y[i]-mid)*(Y[i]-mid));
    }
    cout<<dis<<endl;
    return 0;
}

你可能感兴趣的:(数据结构与算法,基础编程练习)