NOIP 2002 均分纸牌 解题报告

  好题!非常好的贪心题,引用别人的题解吧:

    开始容易想到在所有的牌中找到最多的一堆,然后向小的牌堆上移动,一直到所有的牌都相等,但关键是不知道往哪个方向上移动才能达到移动次数最少。
     设a[i]为第i堆纸牌的张数(0<=i<=n),ave为均分后每堆纸牌的张数,ans为最小移到次数。 
     我们按照由左而右的顺序移动纸牌。若第i堆纸牌的张数a[i]超出平均值,则移动一次(ans+1),将超出部分留给下一堆,既第i+1堆纸牌的张数增加a[i]-ave;若第i堆纸牌的张数a[i]少于平均值,则移动一次(ans+1),由下一堆补充不足部分,既第i+1堆纸牌的张数减少ave-a[i]; 
     问题是,在从第i+1堆中取出纸牌补充第i堆的过程中,可能会出现第i+1堆的纸牌数小于零(a[i+1]-(ave-a[i])<0 )的情况,但由于纸牌的总数是n的倍数,因此后面的堆会补充第i+1堆ave-a[i]-a[i+1]+ ave张纸牌,使其达到均分的要求。 我们在移动过程中,只是改变了移动的顺序,而移动的次数不变,因此此题使用该方法是可行的。
      例如:1  2  27 
      我们从第二堆移出9张到第一堆后,第一堆有10张纸牌,第二堆剩下-7张纸牌,再从第三堆移动17张到第二堆,刚好三堆纸牌数都是10,最后结果是对的,从第二堆移出的牌都可以从第三堆得到。
     此题的原理是贪心,从左到右让每堆牌向平均数靠拢。但负数的牌也可以移动,才是此题的关键。


  我的代码如下:

#include <stdio.h>
#include <stdlib.h>
int num[100];
int n, need = 0;

int srch(void)
{
	int i;
	int ans = 0;
	for(i = 0; i < n - 1; i++){
		if(num[i] != need){
			num[i + 1] += num[i] - need;
			ans++;
		}
	}
	return ans;
}

int main(int argc, char **argv)
{
	int i;
	scanf("%d", &n);
	for(i = 0; i < n; i++){
		scanf("%d", &num[i]);
		need += num[i];
	}
	need /= n;
	printf("%d\n", srch());
	return 0;
}

转载于:https://www.cnblogs.com/yylogo/archive/2011/07/24/NOIP-2002-1.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值