首页 > 代码库 > 【贪心算法】均分纸牌

【贪心算法】均分纸牌

题目:

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

输入:

4

9 8 17 6

输出:

3

 

思路:

让你把每堆纸牌都平分成 总牌数/N 张纸牌,要求用最少的移动次数。

首先,想一个局部解,比如,从左边的一堆开始,即为当前状态,那么当前状态的最优解就是从第二堆里一次就拿够牌,或把多的牌放在第二堆,然后再移第二堆,第三堆……

然后,检测该局部策略是否能够作为全局的贪心策略,很显然,即使是在现实生活中,也是这几步,只不过变了变顺序,你可能会先移动,牌最多的,多的牌分给,牌少的,其实只要牌不够平均数,那么至少要有一步,才能凑够平局数,所以该策略是满足贪心策略。

当然会有一个特殊情况,不过也是正确的,如n=3,① 1② 7③ 22,这时每堆要十张牌,当从第二堆往第一堆拿9张牌时,第二堆变成了-2,仍然按该策略做下去,那么第二堆从第三堆拿12张牌,现在就都是十张牌了,共用了两步,实际情况也是两步,只不过顺序不同。

代码如下:

 

#include <iostream>

using namespace std;

int main()
{
    int dui[100];
    int n;
    int sum=0,p,step=0;
    cin>>n;

    for(int i=0;i<n;i++){
        cin>>dui[i];
        sum+=dui[i];
    }
    p=sum/n;
    for(int i=0;i<n;i++){
        if(dui[i]!=p){
            dui[i+1]+=dui[i]-p;
            dui[i]=p;
            step++;
        }
    }
    cout<<step;
    return 0;
}

 

【贪心算法】均分纸牌