算法导论——输油管道问题解法

                  输油管道问题解法

输油管道问题求的是中位数,用顺序统计量解决。不需要管X坐标,只需要管Y坐标,就OK了。

如果n是奇数,求(n-1)/2的顺序统计量

如果n是偶数,求[N/2,N/2+1]闭区间里面的任意一点,都可以的。程序中采用下中位数

证明如下:

用n为偶数,举例子。

假设T为[N/2,N/2+1]闭区间里面的任意一点,现在移动T距离为d。

当不超过这个区间的时候,必然有N/2的点与管道增加d,N/2的点减少d,所以中的距离不变。

当越过某一个端点的时候,必然有N/2+1的点距离管道增加d,N/2-1的点减少d,所以总的距离在增加。

所以管道在这个[N/2,N/2+1]闭区间里面是最小的铺设费用。

参考:算法导论9.3-9

#include

#include

int partion(int *a,int p,int r){

//划分

int x=a[r];

int i=p-1;

int temp;

for(int j=p;j<r;j++){

if(a[j]<=x){

i++;

        temp=a[j];

a[j]=a[i];

a[i]=temp;

}

}

i++;

temp=a[r];

a[r]=a[i];

a[i]=temp;

return i;

}

int select(int *a,int p,int r,int i){

if(p==r)

return a[p];

int q=partion(a,p,r);

int k=q-p+1;

if(i==k)

return a[q];

if(i

return select(a,p,q-1,i);

else

return select(a,q+1,r,i-k);

}

 

 

int cmp(const voida,const void * b){

return *(int *)a-*(int *)b;

}

 

 

void main(){

//int a[17]={4,9,10,25,36,10,13,16,18,30,27,32,2,6,31,18,19};

int b[17]={4,9,10,25,36,10,13,16,18,30,27,32,2,6,31,18,19};

qsort(b,17,sizeof(b[0]),cmp);

 

for(int i=0;i<17;i++)

printf("%d ",b[i]);

printf("\n");

int t;

    for(int i=1;i<=17;i++){

int a[17]={4,9,10,25,36,10,13,16,18,30,27,32,2,6,31,18,19};

 t=select(a,0,16,i);

printf("%d ",t);

}

printf("\n");

getchar();

getchar();

}

 

上面是测试代码,测试所有的顺序统计量是否正确,从1到n

下面是解决输油管道的代码

void main(){

int a[300];//最多产生300个数据

int b[300];//作为对照

int t;

printf("输油管道问题,请输入产生的随机数的个数\n");

int n;

scanf("%d",&n);

int data;

//printf("%d\n",n);

srand((unsigned) time(NULL));//设置随机数种子

for(int i=0;i

data=rand()%199;

b[i]=a[i]=data;//产生的随机数缩小范围

printf("%d ",data);

}

printf("\n");

int temp;

qsort(b,n,sizeof(b[0]),cmp);//用系统自带的库排序函数

printf("对照的排序好的数据\n");

for(int i=0;i

printf("%d ",b[i]);

printf("\n");

if(n%2){

//n为奇数,取(n-1)/2的顺序统计量

temp=(n-1)/2;

t=select(a,0,n-1,temp);

printf("输油管道的位置在%d\n",t);

}

else{

temp=n/2;//n为偶数取下中位数

t=select(a,0,n-1,temp);

printf("输油管道的位置在%d\n",t);

}

getchar();

getchar();

}

 

你可能感兴趣的:(算法)