输油管道问题(分治)
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.算法设计 inti; while(j!=k){ b=s[0]; for(i=0;i=b){ b=s[i]; l=i; } } m=s[l]; s[l]=s[a-1]; s[a-1]=m; a--; j++; } 5.程序设计 输油管道问题程序如下: #include #include voidsuanfa(); voidzdlch(intb); voidsurt(intk); intN;//全局变量油井数 ints[100];//n 个油井 y 轴坐标 intsumin;//输油管道最小长度 voidmain(){ inti; sumin=0; scanf(“%d“, for(i=0;iN;i++){ scanf(“%d“, scanf(“%d“, } suanfa();//调用关键算法函数 printf(“%d\n“,sumin);} voidsuanfa(){ if(N%2==0)//当油井数是偶数时 surt(N/2); else surt((N+1)/2);//油井是奇数时 } voidsurt(intk)//从大到小第 k 个数是 b 调用 suanfa(b)函数求出路 程{ intj=0,b,l,m; inta=N; inti; while(j!=k){ b=s[0]; for(i=0;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) //求最小长度的总和 { inti; for(i=0;iN;i++) sumin=sumin+(int)fabs(b-s[i]); }