ybt 1320:【例6.2】均分纸牌(Noip2002)
ybt 1828:【02NOIP提高组】均分纸牌
洛谷 P1031 [NOIP2002 提高组] 均分纸牌
设数组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:贪心#includeusing 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; }


![信息学奥赛一本通 1320:【例6.2】均分纸牌(Noip2002) | 1828:【02NOIP提高组】均分纸牌 | 洛谷 P1031 [NOIP2002 提高组] 均分纸牌 信息学奥赛一本通 1320:【例6.2】均分纸牌(Noip2002) | 1828:【02NOIP提高组】均分纸牌 | 洛谷 P1031 [NOIP2002 提高组] 均分纸牌](http://www.mshxw.com/aiimages/31/835965.png)
