• 【贪心算法】均分纸牌


    题目:

    有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;
    }
    祝你早日攒够失望,然后开始新的生活。
  • 相关阅读:
    面向对象并不是必要的
    linq 总结
    垃圾自动回收的一个方案
    随手记 手机软件的不足,和开发自己理财软件的想法
    以人的角度去解决问题
    浮点数比较
    集中原则——软件设计之道
    云在何方
    我遇到了DLL地狱
    在C#.net中如何操作XML
  • 原文地址:https://www.cnblogs.com/LuRenJiang/p/6978262.html
Copyright © 2020-2023  润新知