【贪心】纸牌均分 + 堆泥堆

原创 2018年04月15日 14:32:26

均分纸牌问题的分析:

均分纸牌问题:有 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)。

 先放代码在分析吧,代码比较短。(转自https://www.cnblogs.com/yuchenlin/p/4382027.html)

int main(){
    int N;
    int pokers[MAX];
    cin>>N;
    int total = 0;
    for (int i=0; i<N; i++) {
        cin>>pokers[i];
        total+=pokers[i];
    }
    int avg = total/N,times=0;
    for(int i=0;i<N;i++){
        if(pokers[i]!=avg){
            pokers[i+1] -= avg - pokers[i]; //重要!
            times++;
        }
    }
    cout<<times<<endl; 
}

可以看到最核心的那个循环的思想是这样的:

从第一堆牌开始处理,如果第一堆牌整好是avg那么就放在一边不管了。

如果第一堆牌不是avg,那么就要把第二堆牌(合法的移动只有从2移到1,这也是这个算法的精髓之处)移动几张到第一堆,恰好使第一堆等于avg,从而只考虑第二堆开始到第N堆为止这些堆如何搞的子问题。然后依次递归下去。

这里的一个小技巧是认为牌数可以为负数,这样才能继续下去。综上,这个步骤是合理的。但是看不出来是最优的。可见,贪心法确实是比较容易实现,因为比较符合人类直觉,但是不好证明。

再反过来看一下前面提到的几点,可行性满足,不可取消,每一次操作都是直接赋值,局部最优,当前情况下,只能从右往左移动,且贪心地想尽快让第一堆满足约束。




#include<iostream>
#include<bits/stdc++.h>
using namespace std;
long long a[100005];
long long b[100005];

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		long long n ;
		cin>>n;
		for(int i=1;i<=n;i++)
			scanf("%lld",&a[i]);
		for(int i=1;i<=n;i++)
			scanf("%lld",&b[i]);
		long long sum=0;
		for(int i=1;i<=n-1;i++)
		{
			if(a[i]!=b[i])
			{
				a[i+1]-=(b[i]-a[i]); //注意b[i]和a[i]相减顺序 
				sum+=abs(b[i]-a[i]);
			}
		}
		printf("%lld\n",sum);	
	}
	return 0;
	
}

关键语句

a[i+1]-=(b[i]-a[i]); //注意b[i]和a[i]相减顺序 

意思是,从第一堆开始到倒数第二堆:如果本堆少了,就从右边的那一堆里拿泥巴过来,否则就拿泥巴给右边那堆。(同样是注意认为泥堆可以为负数)。

就这样下去,到最后一堆一定是==b[i]即满足条件的。(不然这题无解)


这道题是埃森哲杯第十六届上海大学生程序设计大赛的A题,自己还是现去学习了纸牌均分问题才明白的.....还是菜了.....加油 !

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_38033475/article/details/79949081

自动生成对表进行插入和更新的存储过程的存储过程

我找到了两个存储过程,能自动生成对一个数据表的插入和更新的存储过程,现在奉献给大家!插入:Create procedure sp_GenInsert@TableName varchar(130),@P...
  • lujun2000
  • lujun2000
  • 2001-11-21 10:13:00
  • 712

002-贪心算法求解“均分纸牌”

给定一堆牌,牌数总量记作cardCount。然后将这些牌分为n个堆,此时牌数总量cardCount必须是牌堆数n的倍数。求解使得移动最少次数的牌,使得n个堆上的牌的数量相等。...
  • qq_31698195
  • qq_31698195
  • 2017-03-15 14:57:57
  • 625

贪心算法-均分纸牌-JAVA

[均分纸牌]有N堆纸牌,编号分别为1,2,…,n。每堆上有若干张,但纸牌总数必为n的倍数.可以在任一堆上取若干张纸牌,然后移动。移牌的规则为:在编号为1上取的纸牌,只能移到编号为2的堆上;在编号为n的...
  • u011035622
  • u011035622
  • 2015-02-08 23:54:07
  • 1499

说难就难的贪心(一)——均分纸牌问题

类型 有N堆纸牌,编号分别为 1,2,…,N。每堆上有若干张,但纸牌总数必为N的倍数。可以在任一堆上取若干张纸牌,然后移动。 移牌规则为:在编号为1的堆上取的纸牌,只能...
  • qq_37656398
  • qq_37656398
  • 2017-08-22 14:26:24
  • 282

wikioi 1098 均分纸牌

题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。   移牌规则为:在编号为 1...
  • kamsau
  • kamsau
  • 2014-10-31 20:18:59
  • 1289

XYNUOJ 1249 均分纸牌(playcard)—贪心算法

欢迎访问XYNUOJ 1249: 均分纸牌(playcard) 时间限制: 1 Sec  内存限制: 128 MB 提交: 11  解决: 7 [提交][状态][讨论版][Edit] ...
  • LiuJiuXiaoShiTou
  • LiuJiuXiaoShiTou
  • 2017-07-31 20:25:10
  • 421

C++贪心算法之均分纸牌

均分纸牌 题目描述 有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。移牌规则为:在编号为 1 堆上取的纸牌,只能移到编...
  • C20190413
  • C20190413
  • 2017-08-18 17:10:15
  • 580

NOip2002均分纸牌

题目描述 有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。 移牌规则为:在编号为 1 堆上取的纸牌,只能移到编号...
  • yyyds
  • yyyds
  • 2016-08-15 20:36:42
  • 1133

codevs均分纸牌 贪心算法

题目描述 Description 有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。   移牌规则为:在编号为 1...
  • glaugagefer
  • glaugagefer
  • 2015-04-21 00:50:22
  • 766

[NOIP2002]均分纸牌题解

题目描述   有 N 堆纸牌,编号分别为 1,2,…, N。每堆上有若干张,但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌,然后移动。   移牌规则为:在编号为 1 堆上取的纸牌,只能移到...
  • wangwei6125
  • wangwei6125
  • 2016-05-30 21:05:49
  • 1505
收藏助手
不良信息举报
您举报文章:【贪心】纸牌均分 + 堆泥堆
举报原因:
原因补充:

(最多只允许输入30个字)