均分纸牌问题
2014-06-09 17:29
155 查看
转载自legendmaner
均分纸牌
[问题描述]
有 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)。
[输 入]:
键盘输入文件名。文件格式:
N(N 堆纸牌,1 <= N <= 100)
A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)
[输 出]:
输出至屏幕。格式为:
所有堆均达到相等时的最少移动次数。‘
[输入输出样例]
a.in:
4
9 8 17 6
屏慕显示:
3
分析:
开始容易想到在所有的牌中找到最多的一堆,然后向小的牌堆上移动,一直到所有的牌都相等,但关键是不知道往哪个方向上移动才能达到移动次数最少。
设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,最后结果是对的,从第二堆移出的牌都可以从第三堆得到。
(再思考:1 10 19,最小的代价显然就是将最后多出9张牌放到第一堆里,但是你只能移动相邻的牌,所以这9张牌先移动到第二堆里,再移动到第一堆里。反过来想,第一堆缺9张牌问相邻的借,如果第二堆有多那就直接借给第一堆好了,这样移动的次数也会最少,如果第二堆也缺的则它本身还要问下一堆所要牌,而且还要将第一堆索要的牌也继续传递下去,当然这样可以先假设其有足够的牌给第一堆,这时将出现负数,但这不是问题,它只相当一个传话的过程(如上一题-7的意思就是第二堆共缺17(10-(-7)=17)张牌,因为本身却8张,而上一堆它还缺9张,所以一共要17张),第二堆刚好合适,可以将第一堆的话传给它相邻的;)
此题的原理是贪心,从左到右让每堆牌向平均数靠拢。但负数的牌也可以移动,才是此题的关键。
int func34(int arr[], int n)
{
assert(arr && n>0);
int i,cnt/*总共移动牌数*/,tm/*移动次数*/;
long avg=0;
int *a;
if (n<2)
{
return 0;
}
a = new int
;
for (i=0; i<n; i++)
{
a[i] = arr[i];
avg += arr[i];
}
avg /= n;
cnt = 0;
tm =0;
for (i=0; i<n-1; i++)
{
if (a[i] - avg != 0 )
{
tm ++;
}
cnt += abs(a[i] - avg);
a[i+1] = a[i+1] + a[i] - avg;
}
delete[] a;
return tm;
}
均分纸牌
[问题描述]
有 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)。
[输 入]:
键盘输入文件名。文件格式:
N(N 堆纸牌,1 <= N <= 100)
A1 A2 … An (N 堆纸牌,每堆纸牌初始数,l<= Ai <=10000)
[输 出]:
输出至屏幕。格式为:
所有堆均达到相等时的最少移动次数。‘
[输入输出样例]
a.in:
4
9 8 17 6
屏慕显示:
3
分析:
开始容易想到在所有的牌中找到最多的一堆,然后向小的牌堆上移动,一直到所有的牌都相等,但关键是不知道往哪个方向上移动才能达到移动次数最少。
设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,最后结果是对的,从第二堆移出的牌都可以从第三堆得到。
(再思考:1 10 19,最小的代价显然就是将最后多出9张牌放到第一堆里,但是你只能移动相邻的牌,所以这9张牌先移动到第二堆里,再移动到第一堆里。反过来想,第一堆缺9张牌问相邻的借,如果第二堆有多那就直接借给第一堆好了,这样移动的次数也会最少,如果第二堆也缺的则它本身还要问下一堆所要牌,而且还要将第一堆索要的牌也继续传递下去,当然这样可以先假设其有足够的牌给第一堆,这时将出现负数,但这不是问题,它只相当一个传话的过程(如上一题-7的意思就是第二堆共缺17(10-(-7)=17)张牌,因为本身却8张,而上一堆它还缺9张,所以一共要17张),第二堆刚好合适,可以将第一堆的话传给它相邻的;)
此题的原理是贪心,从左到右让每堆牌向平均数靠拢。但负数的牌也可以移动,才是此题的关键。
int func34(int arr[], int n)
{
assert(arr && n>0);
int i,cnt/*总共移动牌数*/,tm/*移动次数*/;
long avg=0;
int *a;
if (n<2)
{
return 0;
}
a = new int
;
for (i=0; i<n; i++)
{
a[i] = arr[i];
avg += arr[i];
}
avg /= n;
cnt = 0;
tm =0;
for (i=0; i<n-1; i++)
{
if (a[i] - avg != 0 )
{
tm ++;
}
cnt += abs(a[i] - avg);
a[i+1] = a[i+1] + a[i] - avg;
}
delete[] a;
return tm;
}
相关文章推荐
- 问题 G: 均分纸牌
- xynuoj 均分纸牌问题 酒馆浪人的博客
- CODE[VS]_1098 均分纸牌问题
- 说难就难的贪心(一)——均分纸牌问题
- 均分纸牌及糖果传递问题
- 均分纸牌问题(贪心算法)
- 【算法学习笔记】25.贪心法 均分纸牌问题的分析
- CodeVs_1098 均分纸牌问题
- 天梯 1098 均分纸牌
- 练习赛8.2.均分纸牌
- wikioi 1098 均分纸牌 (2002年NOIP全国联赛提高组)
- 维基oi 1098 均分纸牌
- 均分纸牌
- 【模拟】【NOIP2002】均分纸牌
- 邮票分你一半 N个数最大可能均分 01背包问题
- 关于纸牌均分的解法及扩展
- wikioi-天梯-普及一等-贪心-1098:均分纸牌
- NOIP2002提高组 均分纸牌
- 贪心——均分纸牌
- 【模拟】【NOIP2002】均分纸牌