題目描述:
有\(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; }