1 条题解

  • 0
    @ 2025-8-24 21:20:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 松风之狐
    长歌吟松风,曲尽河星稀。

    搬运于2025-08-24 21:20:07,当前版本为作者最后更新于2019-03-31 16:42:12,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    均分纸牌

    所有堆均达到相等时的最少移动次数。

    一看到最少这个字眼,就应该想到贪心或者动态规划

    而我的思路是:

    因为题目上说:

    纸牌总数必为N的倍数

    现在要求找出一种移动方法,用最少的移动次数使每堆上纸牌数都一样多。

    所以我就想:那么我用每堆的纸牌数去减掉平均数,不就是这堆纸牌需要多少张牌才满足题目条件吗?

    又因为:

    移牌规则为:在编号为1堆上取的纸牌,只能移到编号为2的堆上;在编号为N*的堆上取的纸牌,只能移到编号为N-1的堆上;其他堆上取的纸牌,可以移到相邻左边或右边的堆上。

    所以,如果这堆的纸牌数>0,我们就需要将它的多余纸牌移动到纸牌数<0的纸牌堆上去。

    反之,如果这堆的纸牌数<0,我们就需要将它的缺少的纸牌从纸牌数>0的纸牌堆上移动到它上去。

    于是,有了思路,代码打起来也就非常简单了。

    代码实现:

    #include<iostream>
    #include<cmath>
    using namespace std;
    int n;//纸牌堆数
    int a[10005];//储存纸牌数
    int num=0;//纸牌的平均数
    int ans=0;//移动次数
    int flag=1;//表示纸牌不需要移动
    int main()
    {
    	cin>>n;//输入纸牌堆数
    	for(int i=1;i<=n;i++)
    	{
    		cin>>a[i];//输入每堆的纸牌数
    		num+=a[i];//纸牌的总数进行累加
    	}
    	num/=n;//num变为总纸牌数的平均数
    	for(int i=1;i<=n;i++) a[i]-=num;//将每堆纸牌数变为距离满足条件的纸牌数的数
    	for(int i=1;i<=n;i++) if(a[i]!=0) flag=0;//flag==0,表明需要移动
    	if(flag==0)//需要移动,那么就开始吧!
    	{
    		for(int i=1;i<=n;i++)//从头遍历到尾
    		{
    			if(a[i]>0)//如果它的纸牌数多了
    			{
    				a[i+1]+=a[i];//就把它移动到下一堆去
    				a[i]=0;//这一堆满足条件
    				ans++;//移动次数++
    			}
    			if(a[i]<0)//如果它的纸牌数少了
    			{
    				a[i+1]-=abs(a[i]);//那么它下一堆的纸牌就移动到它上来
    				a[i]=0;//这一堆满足条件
    				ans++;//移动次数++
    			}
    			if(a[i]==0) continue;//如果它满足条件,就不鸟它了。
    		}
    		cout<<ans<<endl;//输出答案
    	}
    	if(flag==1) cout<<ans<<endl;//如果本来就满足条件,直接输出答案(0)
    	return 0;
    }
    
    • 1

    信息

    ID
    33
    时间
    1000ms
    内存
    125MiB
    难度
    2
    标签
    递交数
    1
    已通过
    1
    上传者