本题需要一些基本的线性代数的知识来解决。
首先还是将题目模型化,设n个人分别有x1,x2.......xn个,与均分相差数目为,要使得交换数量最小,我们可以得到一条推论
推论1.任意xi,xi+1间的交换必定是单项的,不可能存在双向交换(证明:容易证明任何双向交换都可以被一次单项交换替代)
于是我们不妨设xi与xi+1间的交换值为pi,这个pi可为正也可为负,因为经过一轮交换后都为0,对p1,p2.......pn列出交换的方程可以得到
;
将n个方程放在一起,构成一个nXn的系数矩阵A,因为将所有方程加起来是0=0的恒等式(即总钱数不变),故矩阵的秩为n-1,detA=0,非齐次线性方程组有无穷解。
可以理解为对于每一初始的p1,都有一组符合条件的解,在这些解中存在一组最小解。这里可以用到基础解系的知识,即非线性方程组的通解等于非线性方程组的特解加上线性方程组的通解,关于特解,可以是人为给出p1后,由函数递归得到的p2-pn,关于通解,则可以显然的观察得知为
(1,1,1.......1)*k,k任意。
且对于初始的p1有范围,min(-as[0],-as[1])<=p1<=max(-as[0],-as[1]),as[i]即为最初的偏差值,在这个范围内枚举即可。
枚举时,不需要每次都调用函数递归,直接对于第一组特解加上(1,1,1.......1)*k即可。
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int anwser[10000];
int n,r=0;
while(1){
cin>>n;
if(n==0)break;
int a[n];
int i,s=0;
for(i=0;i<=n-1;i++){
cin>>a[i];
s=s+a[i];
}
int avg;
avg=s/n;
int as[n];
for(i=0;i<=n-1;i++){
as[i]=(a[i]-avg);
}
int mini,finalmini=100000000;
int b[n],j;
for(j=min(-as[0],-as[1]);j<=max(-as[0],-as[1]);j++){
b[0]=j;
mini=0;
for(i=0;i<=n-1;i++){
b[i+1]=b[i]+as[i];
}
for(i=0;i<=n-1;i++){
mini=mini+abs(b[i]);
}
if(mini<finalmini) finalmini=mini;
}
anwser[r]=finalmini;
r++;
}
int i;
for(i=0;i<=r-1;i++){
cout<<anwser[i]<<endl;
}
return 0;
}