洛谷P1031 均分纸牌

题目描述
有N堆纸牌,编号分别为 1,2,…,N。每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。
移牌规则为:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为N的堆上取的纸牌,只能移到编号为N−1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。例如N=4,4堆纸牌数分别为:
①9②8③17④6移动3次可达到目的:
从 ③ 取4张牌放到 ④ (9,8,13,10)-> 从 ③ 取3张牌放到 ②(9,11,10,10)-> 从 ② 取1张牌放到①(10,10,10,10)。

输入输出格式
输入格式:
两行第一行为:N(N 堆纸牌,1≤N≤100)第二行为:A1,A2,…,An​ (N堆纸牌,每堆纸牌初始数,1≤Ai≤10000)
输出格式:
一行:即所有堆均达到相等时的最少移动次数。

输入输出样例
输入样例#1:
4
9 8 17 6
输出样例#1:
3

思维题:
这道题我推了半天感觉很难啊,分了好几种情况,又是找最大值,又是判断左右区间,很乱,而且还理不清思路。
题解的意思是,先计算平均值,然后每个数都减去平均值,这样得到的数列就是以0为均值的数列,大于零代表比均值多的数量,小于零代表比均值少的数量。在拿的时候也不用去找多的看如何分给少的,直接从左至右把值往右加,因为把少的拿给多的和把多的拿给少的是一样的。注意前导零要排除,中间加到0的那一部不计步数。

代码:

#include<iostream>
using namespace std;
//P1031 均分纸牌
int main()
{
 int N, ave, sum = 0, tmp = 0, ans = 0, a[10005];//N是堆数,ave是均值,sum用来计算总和,tmp用来存移动时加给下一个数的值,ans记录移动次数,数组a存数
 cin >> N;
 for (int i = 0; i < N; i++)//输入数据并计算总和
 {
  cin >> a[i];
  sum += a[i];
 }
 ave = sum / N;//计算均值
 for (int i = 0; i < N; i++)//每个值减去均值
 {
  a[i] -= ave;
 }
 tmp = 0;
 for (int i = 0; i < N; i++)//模拟计算步数
 {
  if (a[i] == 0 && tmp == 0)//如果有前导零,跳过
   continue;
  a[i] += tmp;//a[i]加上前一步传过来的数
  tmp = a[i];//更新tmp为当前剩余的值
  if(tmp!=0)//如果剩余为0,说明前一个数加过来刚好补齐这一个数缺的/多的,就不用往后加0了;如果剩余不为零,就步数加一
   ans++;
 }
 cout << ans << endl;
 //system("pause");
 return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章