NOJ ACM-ICPC Redistribute wealth

本题需要一些基本的线性代数的知识来解决。

首先还是将题目模型化,设n个人分别有x1,x2.......xn个,与均分相差数目为\Delta x_{i},要使得交换数量最小,我们可以得到一条推论

推论1.任意xi,xi+1间的交换必定是单项的,不可能存在双向交换(证明:容易证明任何双向交换都可以被一次单项交换替代)

于是我们不妨设xi与xi+1间的交换值为pi,这个pi可为正也可为负,因为经过一轮交换后\Delta x_{i}都为0,对p1,p2.......pn列出交换的方程可以得到

p_{i+1}=p_{i}+\Delta x_{i};

将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;
}
 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值