输油管道问题(分治)
1. 问题描述
输油管道问题描述如下:
某石油公司计划建造一条由东向西的主输油管道。该管道要穿过一个有
n 口油井的油田。从每口油井都要有一条输油管道沿最短路经(或南或北)与主管
道相连。如果给定n口油井的位置,即它们的x 坐标(东西向)和y 坐标(南北
向),应如何确定主管道的最优位置,即使各油井到主管道之间的输油管道长度总
和最小的位置? 证明可在线性时间内确定主管道的最有位置。给定n 口油井的
位置,编程计算各油井到主管道之间的输油管道最小长度总和。
2. 问题分析
如果只有一口井,那么显然是越近越好,即建在油井上; 如果有两口井,
那么显然是有以下三种情况:
1.两口井都在主管道北边,那么这个时候的两个连接管道的长度和肯定大于
两口井的Y坐标之差
2.两口井都在主管道南边,和情况1是一样的
3.两口井,一个在主管道南边,一个在主管道北边,那么两个连接管道的长
度和就等于两口井的Y坐标之差 显然情况三是所要的最小管道长度的设计情
况
就是当主管道在两口井之间的任意位置时,连接管道长度之和都等于两口井
的Y坐标之差,是最小的长度
那么将这个结论推广,当有n口井的时候, 1.n是偶数
只要这n口井分布在主管道的两边,一边n/2个,那么就是距离之和最小
的 2.n是奇数
只要将这n个井中,Y坐标最中间的(也就是Y是中值的那个)井不算,其
余的偶数个井分布在主管道的两侧,这个时候移动主管道,那么这n个连接管道
长度之和就决定于那个没有算的井了,因为其余的井的距离之和是固定了的,这
个时候只要主管道最接近那个点就好了呀
3.数据结构设计
用N来表示油井的数目,用数组s[]来记录N个油井的y坐标,通过对N%2
的判断来判断N是否为偶数,如果是则用surt(N/2)来求路程,否则用(N+1)
/2来求,对于surt()函数,是来计算路程的, 用while循环,把Y坐标大地
的记录在数组的后面,最后用zdlch()函数通过对sumin的累加来计算最小的
长度之和。
4.算法设计
int i;
while(j!=k){
b=s[0];
for(i=0;i
if(s[i]>=b){
b=s[i];
l=i;
}
}
m=s[l];
s[l]=s[a-1];
s[a-1]=m;
a--;
j++;
}
5.程序设计
输油管道问题程序如下:
#include
#include
void suanfa();
void zdlch(int b);
void surt(int k);
int N;//全局变量 油井数
int s[100];//n个油井y轴坐标
int sumin;//输油管道最小长度
void main() {
int i;
sumin=0;
scanf("%d",&N);
for(i=0;i
scanf("%d",&s[i]);
scanf("%d",&s[i]);
}
suanfa();//调用关键算法函数
printf("%d\n",sumin); }
void suanfa() {
if(N%2==0)//当油井数是偶数时
surt(N/2);
else
surt((N+1)/2);//油井是奇数时
}
void surt(int k)//从大到小第k个数是b调用suanfa(b)函数求出路
程 {
int j=0,b,l,m;
int a=N;
int i;
while(j!=k) {
b=s[0];
for(i=0;i
if(s[i]>=b)
{
b=s[i];
l=i;
}
}
m=s[l];s[l]=s[a-1];s[a-1]=m;a--;j++;
}
zdlch(b);
}
Void zdlch(int b) //求最小长度的总和 {
int i;
for(i=0;i
sumin=sumin+(int)fabs(b-s[i]);
}