输油管道问题解法
输油管道问题求的是中位数,用顺序统计量解决。不需要管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 void* a,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();
}