栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

信息学奥赛一本通 1320:【例6.2】均分纸牌(Noip2002) | 1828:【02NOIP提高组】均分纸牌 | 洛谷 P1031 [NOIP2002 提高组] 均分纸牌

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

信息学奥赛一本通 1320:【例6.2】均分纸牌(Noip2002) | 1828:【02NOIP提高组】均分纸牌 | 洛谷 P1031 [NOIP2002 提高组] 均分纸牌

【题目链接】

ybt 1320:【例6.2】均分纸牌(Noip2002)
ybt 1828:【02NOIP提高组】均分纸牌
洛谷 P1031 [NOIP2002 提高组] 均分纸牌

【题目考点】 1. 贪心 【解题思路】 解法1:贪心

设数组a,a[i]表示第i堆纸牌的数量,一共有n堆纸牌。由于最后要均分纸牌,每堆牌最后的数量为纸牌总数除以n,记每堆纸牌平均数量为ave。
考虑第1堆纸牌,第1堆纸牌的数量只能通过从第2堆拿或分给第2堆来改变,有以下几种情况:

  • 如果第1堆纸牌的数量等于ave,则不移动纸牌,看下一堆。
  • 如果第1堆纸牌的数量大于ave,则需要分给第2堆a[1]-ave张纸牌,第2堆纸牌增加a[1]-ave。
  • 如果第1堆纸牌的数量小于ave,则需要从第2堆拿来ave-a[1]张纸牌,第2堆纸牌减少ave-a[1],也可以说成第2堆纸牌增加a[1]-ave,不过增加的是负数。

如果第2堆纸牌数量a[2]小于ave-a[1],那么第2堆在分给第1堆纸牌后,第2堆的纸牌数量为负数,这也没关系,就当它有负数张纸牌。

a[i]为负数,其意义为“还需要从后面牌堆获取a[i]张纸牌来分给前面的牌堆”。实际过程为,会先从第3堆调度足够的纸牌到第2堆,然后再分给第1堆。如果第3堆的纸牌也不够呢?会先从第4堆及以后的纸牌调度给第3堆,依此类推。似乎是要进行多次纸牌移动,但实际是在考虑完所有情况,计算好前面的纸牌堆需要的纸牌数量后,相邻的纸牌堆之间只会移动一次纸牌。

在处理完第1堆后,考虑第2堆纸牌。第1堆已经有ave张纸牌了,第2堆纸牌不用再考虑与第1堆的纸牌交换,只需要考虑与第3堆的纸牌交换。思考过程与上述情况类似。
一般地,在考虑第k堆纸牌时,第k堆纸牌的数量只能通过与第k+1堆纸牌交互才可以发生改变

  • 如果第k堆纸牌的数量等于ave,则不移动纸牌,看下一堆。
  • 如果第k堆纸牌的数量不等于ave,则移动纸牌,需要分给第k+1堆a[k]-ave张纸牌。(a[k]-ave为正数或负数,如果为负数,是指第k+1堆分给第k堆ave-a[k]张纸牌)

该过程不断进行,直到考虑第n-1堆,当第n-1堆也是ave张纸牌时,剩下的纸牌数量一定是ave张,第n堆自然就是ave张纸牌了。

【题解代码】 解法1:贪心
#include
using namespace std;
int n, a[101], ct;//a[i]:第i堆纸牌的数量 ct:移牌次数 
int main(){
    int ave, sum = 0;//sum:纸牌总和 ave:平均每堆纸牌的数量 
	cin >> n;
	for(int i = 1; i <= n; i++)
    {
		cin >> a[i];
		sum += a[i];//纸牌总数加和 
	}
	ave = sum / n;//纸牌总数一定是n的倍数,所以一定可以整除 
	for(int i = 1; i <= n-1; i++)
	{
		if(a[i] != ave)//如果第i堆不是ave张 
        {
			a[i+1] = a[i+1] + a[i] - ave;//第i+1堆增加a[i]-ave张,或第i+1堆减少ave-a[i]张。 
			ct++;//移动次数加1 
		}
	}
	cout << ct;
	return 0;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/835965.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号