阿里巴巴2013笔试题 最后大题的分析(网络资料整理)

四、综合题

有一个淘宝商户,在某城市有n个仓库,每个仓库的储货量不同,现在要通过货物运输,将每次仓库的储货量变成一致的,n个仓库之间的运输线路围城一个圈,即1->2->3->4->...->n->1->...,货物只能通过连接的仓库运输,设计最小的运送成本(运货量*路程)达到淘宝商户的要求,并写出代码。

解答:这个题目类似的题目有:

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1045
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传
递一个糖果代价为1,求使所有人获得均等糖果的最小代价。
分析:
假设a1分给an的糖果数为k,则可以得到以下的信息:
  a1              a2                        a3           an-1              an
当前数目:a1-k           a2         a3           an-1              an+k
所需代价:|a1-k-ave| |a1+a2-k-2*ave| |a1+a2+a3-k-3*ave||a1+..+a(n-1)-k-(n-1)*ave|   |k|
以sum[i]表示从a1加到ai减掉i*ave的和值,这以上可以化简为
总代价 = |s1-k|+|s2-k|+...+|s(n-1)-k|+|k|
不难看出:当k为s1...s(n-1)中的中位数的时候,所需的代价最小



但从上面的讲解看的话,还是很难理解,不过下面的博客则是从数学的角度给出了上述公式的来源

解析:这道题用骗分的方法,只能得10分 到20 分。 看看数据,100W,就知道要用线性或者 nlogn的算法。

而且,nlogn的算法也不能用上很多的常数级,要不照样超时。

这道题完全是数学方法,

设第i个小朋友分给第i-1个小朋友的糖果数为Pi(注意, Pi可正可负负数理解成为第i-1个小朋友分给第i个小朋友-Pi个糖果),P1为第一个小朋友分给第n个小朋友的, 显然最后的答案就是要求|P1|+|P2|+..+|Pn|的最小值.

而我们的最总目的是,将pi全部用p1表示。

设ave为最终每个人拿到的糖果数目,也就是平均数。

则avei=-pi+pi+1+a[i], 在设 w[i]=avei-a[i] 则变成 w[i]=-pi+pi+1

设s[i]=w[1]+w[2]+…+w[i] 则pi=p1+s[i-1]

|P1|+|P2|+..+|Pn|=|p1|+|p1+s[1]|+..+|P1+s[n-1]|

设Q=-p1

则 原式变为|0-Q|+|s[1]-Q|+..+|s[n-1]-Q|

这个式子可以看成 求 0,s[1],s[2]…s[n-1]到 Q的 最短距离之和,

这这个数列的中位数就是Q值。



#include
#include
#include
#include
using namespace std;

int a[1000009];
int s[1000009];

long long mabs(long long a)
{
if(a<0)a=-a;
return a;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
long long i,all=0,mid,temp;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
all+=a[i];
s[i]=all;
}
temp=all/n;
for(i=1;i<=n;i++)
{
s[i]-=temp*i;
}

sort(&s[1],&s[n+1]);
mid=s[(n+1)/2];
all=0;
for(i=1;i<=n;i++)
{
all+=mabs(s[i]-mid);
}

printf("%lld\n",all);
}

return 0;
}






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