Time Limit: 2second
Memory Limit: 2 MB
有n堆纸牌,编号分别为1,2....n。每堆上有若干张,但纸牌总数必为n的倍数。可以在任一堆上取若干张纸牌,然后移动。
移动规则为:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为n堆上取的纸牌,只能移到编号为n-1的堆上;其他堆上取的纸牌,可以移动到相邻左边或者右边的堆上。
现在要求找出一种移动方法,用最少的移动次数使每堆上的纸牌数都一样多。
例如n=4,4堆纸牌数分别为①9 ②8 ③17 ④6
移动3次可达到目的:
从③取4张纸牌放到④(9 8 13 10)
从③取4张纸牌放到②(9 11 10 10)
从②取4张纸牌放到①(10 10 10 10)
Input
输入文件两行。
第一行输入n(1≤n≤100)。
第二行输入a1 a2 .... an(每堆纸牌初始数,1≤ai≤10000)
Output
所有堆均达到相等的最少移动次数(最后用换行结束)
Sample Input
4 9 8 17 6
Sample Output
3
【题解】
这题要特别注意一点,“其他堆上取的纸牌,可以移动到相邻左边或者右边的堆上。”,即只能移到相邻的牌堆上。知道这一点后我们可以先考虑第一堆。
先求出平均数ave,如果第一堆牌数小于ave,只能从第二堆拿所需要的,让第一堆数目到ave。接下来第二堆,如果再从第一堆拿牌到第二堆,显然是不划算的,只能从第3堆拿或者第二堆多了 拿到第3堆去(还是要强调,题目要求只能从相邻牌堆拿),这样一直下去,到了第n-1堆,前N-1堆排好了,第n堆自然也就排好了,因为是n的倍数。
【代码】
#include <cstdio> int a[150],n,ans = 0; void input_data() { scanf("%d",&n); for (int i = 1;i <= n;i++) scanf("%d",&a[i]); } void get_ans() { int ave = 0; for (int i = 1;i <= n;i++) ave += a[i]; ave /= n; //先算出平均数 for (int i = 1;i <= n-1;i++) //开始移动 { if (a[i] != ave) ans++; //如果第i堆不是等于平均数,则一定要移,那么就增加操作数 a[i+1] = a[i+1] + a[i] - ave; //直接增加第i+1堆 a[i] - ave ,负数则变成减的 a[i] = ave; //a[i]一定可以变成ave。 } } void output_ans() { printf("%d ",ans); } int main() { input_data(); get_ans(); output_ans(); return 0; }