某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有n口油井的油田。从每口油井都要有一条输油管道沿最短路经(或南或北)与主管道相连。
如果给定n口油井的位置,即它们的x坐标(东西向)和y坐标(南北向),应如何确定主管道的最优位置,即使各油井到主管道之间的输油管道长度总和最小的位置?
如果有两口油井,取两口油井南北方向之间的任意位置
如果有三口油井,则取中位数。
n口油井即为找中位数
下面用分治的思想求中位数,而不是用C语言自带的sort()函数
#include<stdio.h>
#include<stdlib.h>//abs()求绝对值函数的头文件
#define N 10010
int b[N],a[N];
void swapAij(int i,int j)
{
int temp;
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
int SearchMid(int s,int e,int t)//从a[s]到a[e],找第t小的
{
int nleft=0;
//printf("从a[%d]到a[%d]查找第%d小的数\n",s,e,t);
//for(int k=s; k<=e; k++)
//printf("%d ",a[k]);
//printf("\n");
int i,j=e;
//用i,j分别从左到右,从右到左进行遍历使比a[s]小或等于a[s]的都在左子集中,用nleft计数
for(i=s+1; i<=j; i++)
{
if(a[i]<=a[s])
nleft++;//左子集中的个数加一
//a[i]>a[s]时,从右到左找a[j]<=a[s]
//交换两个数a[i]和a[j],nleft++
else
{
for(; j>i; j--)
if(a[j]<=a[s])
{
swapAij(i,j);//交换
nleft++;//左子集个数++
}
}
}
//a.未比较a[j]时,i=e且比较a[i]和a[s]后退出循环
//b.比较过a[j]时,a[j]>a[s],i=j退出循环
//左子集的个数等于t-1,则找到了第t小的数a[s]
if(nleft+1==t)
return a[s];
//左子集的个数nleft小于t-1,则舍弃左子集和a[s],找右子集中第t-nleft-1个
else if(nleft+1<t)
SearchMid(s+nleft+1,e,t-nleft-1);
//nleft+1>t,在左子集中找第t小的数
else
SearchMid(s+1,i-1,t);
}
int main()
{
int n,mid,sum=0;
scanf("%d",&n);
for(int i=0; i<n; i++)
scanf("%d %d",&b[i],&a[i]);
mid=SearchMid(0,n-1,n/2+1);//求中位数即 从a[0]到a
[n-1]找第n/2-1小的
//printf("mid=%d\n",mid);
for(int i=0; i<n; i++)
sum+=abs(a[i]-mid);
printf("%d",sum);
return 0;
}
/*
输入样例
5
1 2
2 2
1 3
3 -2
3 3
5
1 3
3 -2
3 3
1 2
2 2
输出样例
6
*/