20 May 2014

题目

Problem Description

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

Input

第一行N(N 堆纸牌,1 <= N <= 100)
第二行A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)

Output

输出至屏幕。格式为:
所有堆均达到相等时的最少移动次数。

Sample Input

4
9 8 17 6

Sample Output

3

解题思路

贪心算法,从前面开始,如果大于平均数,将多出来的牌放后面一堆上面;如果小于平均数,则向后面拿牌。不用担心后面的堆纸牌数为负,可以理解成先欠着牌,因为最终会达到平均数,后面总会有牌传过来的。

解题代码

//
//  main.cpp
//  均分纸牌
//
//  Created by Yeah on 13-11-12.
//  Copyright (c) 2013年 Yeah. All rights reserved.
//

#include <iostream>
#include <vector>
using namespace std;

int main()
{
    unsigned int N(0);
    while (cin >> N/* && N != 0)*/)
    {
        unsigned int Move(0);
        int Sum(0);
        vector<int> vec;
        for (unsigned int i(0); i != N; ++i)
        {
            int temp(0);
            cin >> temp;
            Sum += temp;
            vec.push_back(temp);
        }
        int Average(Sum / N);
        for (vector<int>::iterator iter(vec.begin()); iter != vec.end() - 1; ++iter)
        {
            if (*iter != Average)
            {
                if (*iter > Average)
                {
                    *(iter + 1) += *iter - Average;
                    *iter -= *iter - Average;
                    Move++;
                }
                else
                {
                    *(iter + 1) -= Average - *iter;
                    *iter += Average - *iter;
                    Move++;
                }
            }
        }
        cout << Move << endl;
    }
    return 0;
}
题目链接Wikioi 1098


blog comments powered by Disqus