【題解】P1440 均分紙牌

均分紙牌

題目描述:
\(N\)堆紙牌,編號分別爲\(1,2,…,N\)。每堆上有若干張,但紙牌總數必爲\(N\)的倍數。能夠在任一堆上取若干張紙牌,而後移動。ios

移牌規則爲:在編號爲\(1\)堆上取的紙牌,只能移到編號爲\(2\)的堆上;在編號爲\(N\)的堆上取的紙牌,只能移到編號爲\(N-1\)的堆上;其餘堆上取的紙牌,能夠移到相鄰左邊或右邊的堆上。spa

如今要求找出一種移動方法,用最少的移動次數使每堆上紙牌數都同樣多。code

分析:

全部堆均達到相等時的最少移動次數。ci

一看到最少這個字眼,就應該想到貪心或者動態規劃get

而個人思路是:io

由於題目上說:class

紙牌總數必爲N的倍數stream

如今要求找出一種移動方法,用最少的移動次數使每堆上紙牌數都同樣多。遍歷

因此我就想:那麼我用每堆的紙牌數去減掉平均數,不就是這堆紙牌須要多少張牌才知足題目條件嗎?方法

又由於:

移牌規則爲:在編號爲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;
}
相關文章
相關標籤/搜索