思路:贪心算法。
所谓贪心,贪得是什么?有么有做到局部的最优带来全局的最优,,
从左往右扫,一直让每一堆的卡片都为0,只要最开始的满足了,而且是一步一步过滤过来的,那么最终的结果定满足都是0,,,
(看不懂不要急,,,慢慢看分析)
第一步:求出每一堆纸牌的最终结果,也就是最后每一堆纸牌的张数。
第二步:将每一堆纸牌的数目进行更新,也就是最终值与现在值的差,可以存在负值,负值也是有意义的。
从头部和尾部开始,同时对每一堆进行过滤,将为0的堆去掉,重新设置开头和结尾。
第三步:写一个while循环来进行每堆纸牌间的移动,核心代码:s[i+1] +=s[i];s[i] = 0;ans++;i++;while( s[i] == 0 )i++;
切记:在移牌的过程中,一定要时时刻刻的过滤,我一开始就是没注意到这一点,WA了好多数据。。。。至于为什么要在移牌的过程中进行
过滤,这个大家可以假设 更新完数组后的情况为: -3 3 5 -2 ................ ,开始,-3移动到3 -> 0 0 5 -2.......... , 如果没有过滤到第二个0的话,
那么,i就会从第二堆开始,进行重复的工作,但是,第二堆本来就是0了,即,我们不需要再移动纸牌了,,所以,这样的话,就多算了一次。
下来再来讲讲为什么有的堆中能出现 负数的纸牌情况,先这样想,把第i堆的-3张牌移动到第i+1堆去,是不是等价于 把i+1堆的3张牌移动到第i堆去,
这个就类似与我们所选择的参考对象了,,有点物理的小知识了。。。。。
下面是代码:
# include<cstdio>
# include<iostream>
using namespace std;
int s[100+6];
int main(void)
{
int n;cin>>n;
int sum = 0;//计算这几个数字的和
int ans = 0;//保存输出的结果
for ( int i = 1;i <= n;i++ )
{
cin>>s[i];
sum+=s[i];
}
int ave = sum/n;
for ( int i = 1;i <= n;i++ )
{
s[i]-=ave;
}
int i = 1;//i从头开始
int j = n;//j从尾开始
while ( s[i]==0&&i<n ) i++;//从头过滤
while ( s[j]==0&&j>0 ) j--;//从尾部开始过滤
while ( i<j )
{
s[i+1]+=s[i];
s[i] = 0;
i++;
ans++;
while( s[i]==0&&i<j )i++;//移动牌的过程中开始过滤
}
cout<<ans<<endl;
return 0;
}