zoukankan      html  css  js  c++  java
  • CH0501 货仓选址(第k小数)

    描述
    在一条数轴上有N家商店,它们的坐标分别为 A[1]~A[N]。现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
    输入格式
    第一行一个整数N,第二行N个整数A[1]~A[N]。
    输出格式
    一个整数,表示距离之和的最小值。
    样例输入
    4
    6 2 9 1
    样例输出
    12
    数据范围与约定
    对于100%的数据: N<=100000, A[i]<=1000000

    这是一道裸的中位数题,但本人不想用快排,于是用了求第k小数的做法(不完全排序)。
    方法1(快排):

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=1e5+10;
    int n,a[N],p;long long ans;
    #define  g getchar()
    void qr(int &x)
    {
    	char c=g;x=0;bool v=0;
    	while(!(('0'<=c&&c<='9')||c=='-'))c=g;
    	if(c=='-')v=1,c=g;
    	while('0'<=c&&c<='9')x=x*10+c-'0',c=g;
    	if(v)x=-x;
    }
    int main()
    {
    	qr(n);
    	for(int i=0;i<n;i++)qr(a[i]);
    	sort(a,a+n);
    	p=(n>>1)-1;
    	for(int i=0;i<p;i++)ans+=a[p]-a[i];
    	for(int i=p+1;i<n;i++)ans+=a[i]-a[p];
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    

    方法2(第k小数):

    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #define g getchar()
    using namespace std;
    const int N=1e5+10;
    void qr(int &x)
    {
    	char c=g;x=0;
    	while(!('0'<=c&&c<='9'))c=g;
    	while('0'<=c&&c<='9')x=x*10+c-'0',c=g;
    }
    int a[N],n,k;
    int random(int x){return rand()%x;}//取[0,x-1]中的数 
    int find(int l,int r)//查基准值排名 
    {
    	int p=random(r-l+1)+l,x=a[p];//随机基准值。
    	swap(a[l],a[p]);
    	while(l<r)
    	{
    		while(a[r]>=x&&l<r)--r;
    		a[l]=a[r];
    		while(a[l]<=x&&l<r)++l;
    		a[r]=a[l];
    	}
    	a[l]=x;
    	return l;
    }
    int dfs(int l,int r)//返回第k小数 
    {
    	int t=find(l,r);
    	if(t<k)return dfs(t+1,r);
    	else if(t==k)return a[t];
    	else return dfs(l,t-1);
    }
    int main()
    {
    	srand(time(0));
    	qr(n);k=(n+1)>>1;
    	for(int i=1;i<=n;i++)qr(a[i]);
    	int p=dfs(1,n);
    	long long ans=0;
    	for(int i=1;i<k;i++)ans+=p-a[i];
    	for(int i=k+1;i<=n;i++)ans+=a[i]-p;
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    这是运用分治的思想。
    但是,可能大家会不理解find函数为什么就能把[l,r]分成不大于基准值和不小于基准值的两块。不要急,且听我娓娓道来~~

    int find(int l,int r)//查基准值排名 
    {
    	int p=random(r-l+1)+l,x=a[p];//随机基准值。
    	swap(a[l],a[p]);
    	while(l<r)
    	{
    		while(a[r]>=x&&l<r)--r;
    		a[l]=a[r];
    		while(a[l]<=x&&l<r)++l;
    		a[r]=a[l];
    	}
    	a[l]=x;
    	return l;
    }
    

    首先,我们可以看出x就是选出的随机基准值。
    次之,我们可以用赋值环来解释这样做的正确性。
    设第i次进入循环,执行第一个赋值时的li,ri左右指针分别为l_i,r_i,执行第二个赋值时的li+1,ri左右指针分别为l_{i+1},r_i,一共进入k次循环。
    如果我们把赋值看作有向边的话,很明显可以想出,图应该是这样的:
    l1&lt; r1&lt;l2&lt;lk&lt;rk&lt;lk+1&lt;l_1&lt;- r_1 &lt;- l_2……&lt;-l_k&lt;-r_k&lt;l_{k+1}(&lt;-表示有向边)
    最后,我们把l1l_1的初值赋值给lk+1l_{k+1}就相当于对(2k+1)个数进行了交换。同时也把[l,r]分成不大于基准值和不小于基准值的两块。

  • 相关阅读:
    spring初始化bean时执行某些方法完成特定的初始化操作
    flask与数据库连接相关操作
    解决flask中文乱码的问题
    flask(1)
    First Unique Character in a String (找到一个字符串中第一个不重复的字符)
    Java hashCode() 方法
    Java 类和对象
    Java 一维数组的定义和初始化
    Maven 在运行部署的时候是如何确定推送到 releases 还是 snapshots 仓库的
    Samples for Parallel Programming with the .NET Framework
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373924.html
Copyright © 2011-2022 走看看