【3001】均分纸牌

Time Limit: 2second
Memory Limit: 2 MB

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

Input

输入文件两行。
第一行输入n(1≤n≤100)。
第二行输入a1 a2 .... an(每堆纸牌初始数,1≤ai≤10000)

Output

所有堆均达到相等的最少移动次数(最后用换行结束)

Sample Input

4
9 8 17 6

Sample Output

3

【题解】

这题要特别注意一点,“其他堆上取的纸牌,可以移动到相邻左边或者右边的堆上。”,即只能移到相邻的牌堆上。知道这一点后我们可以先考虑第一堆。

先求出平均数ave,如果第一堆牌数小于ave,只能从第二堆拿所需要的,让第一堆数目到ave。接下来第二堆,如果再从第一堆拿牌到第二堆,显然是不划算的,只能从第3堆拿或者第二堆多了 拿到第3堆去(还是要强调,题目要求只能从相邻牌堆拿),这样一直下去,到了第n-1堆,前N-1堆排好了,第n堆自然也就排好了,因为是n的倍数。

【代码】

#include <cstdio>

int a[150],n,ans = 0;

void input_data()
{
    scanf("%d",&n);
    for (int i = 1;i <= n;i++)
        scanf("%d",&a[i]);
}

void get_ans()
{
    int ave = 0;
    for (int i = 1;i <= n;i++)
        ave += a[i];
    ave /= n; //先算出平均数
    for (int i = 1;i <= n-1;i++) //开始移动
        {
            if (a[i] != ave) ans++; //如果第i堆不是等于平均数,则一定要移,那么就增加操作数
            a[i+1] = a[i+1] + a[i] - ave; //直接增加第i+1堆 a[i] - ave ,负数则变成减的
            a[i] = ave; //a[i]一定可以变成ave。
        }
}

void output_ans()
{
    printf("%d
",ans);
}

int main()
{
    input_data();
    get_ans();
    output_ans();
    return 0;
}



 

原文地址:https://www.cnblogs.com/AWCXV/p/7632456.html