【题解】均分纸牌

题目描述

        有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);

        第二行为N个整数,表示每堆纸牌初始数Ai(1≤Ai≤10000)。

输出格式

        所有堆均达到相等时的最少移动次数。

扫描二维码关注公众号,回复: 6088342 查看本文章

输入样例

4

9 8 17 6

输出样例

3

 

题解

        容易发现,纸牌数一样多实际上就相当于是每一位都变成纸牌数总和的平均数。

        把每一位的数量都减去平均数,就是这一位需要移动的纸牌。

        显然所有位加起来后就为0,那么可以从左加到右,这样肯定是最优情况(这里把负数情况也看做移动)。(原因:每一位最多只用移动一次)

#include <iostream>
#include <cmath>
#define MAXN 102

using namespace std;

int n;
int a[MAXN];
int l, r; 
int sum;
int ans;

int main()
{
    cin >> n;
    for(register int i = 1; i <= n; i++)
    {
        cin >> a[i];
        sum += a[i];
    }
    sum /= n;//求平均值 
    for(register int i = 1; i <= n; i++)
    {
        a[i] -= sum; 
    } 
    l = 1;
    r = n;
    while(!a[l]) l++; //去除无用0 
    while(!a[r]) r--; //同上 
    while(l < r)// 把问题转换为 给正数纸牌  加上负数纸牌 最后必然变为0 
    {
        a[l + 1] += a[l];
        a[l] -= a[l];
        ans++;
        while(!a[l]) l++;// 同上 
    }
    cout << ans;
    return 0;
    return 0;
}
参考程序

猜你喜欢

转载自www.cnblogs.com/kcn999/p/10800514.html
今日推荐