【题目链接】
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<bits/stdc++.h>
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;
}