1 題目描述
有N堆紙牌,編號分別爲1,2,…,N。每堆上有若干張,但紙牌總數必爲N的倍數。可以在任一堆上取若干張紙牌,然後移動。
移牌規則爲:在編號爲1堆上取的紙牌,只能移到編號爲2的堆上;在編號爲N的堆上取的紙牌,只能移到編號爲N−1的堆上;其他堆上取的紙牌,可以移到相鄰左邊或右邊的堆上。
現在要求找出一種移動方法,用最少的移動次數使每堆上紙牌數都一樣多。
例如N=4,4堆紙牌數分別爲:
①9②8③17④6
移動3次可達到目的:
從 ③ 取4張牌放到 ④ (9,8,13,10)-> 從 ③取3張牌放到 ②(9,11,10,10)-> 從②取1張牌放到①(10,10,10,10)。
2 輸入輸出格式
輸入格式:
兩行
第一行爲:N(N堆紙牌,1≤N≤100)
第二行爲:A1,A2,…,An(N堆紙牌,每堆紙牌初始數,l≤ Ai ≤10000)
輸出格式:
一行:即所有堆均達到相等時的最少移動次數。
輸入輸出樣例 輸入樣例#1: 4 9 8 17 6
輸出樣例#1: 3
3 分析
這是一道經典的貪心算法入門題目,要想用最少的移動次數把所有牌堆都移到相等,正確的貪心策略顯然是:每次都移動儘可能多的紙牌。
以正常人的思維來想,肯定是從紙牌數最多的牌堆開始往旁邊的牌堆移動紙牌,但是如果要程序中模擬這個過程無疑是比較困難的。因爲是計算機處理的緣故,我們可以移動負數張紙牌,且最後達到的效果一樣。
一開始先求出牌數的平均值,然後從第1堆開始遍歷到第n-1堆牌,如果堆中的牌數不等於平均值,就移動堆中的牌數與平均值的差值張牌(這裏無論正負)。接着,下一堆接收到移動過來的牌後,如果牌數不等於平均值,就移動差值張牌…如此循環反覆,計算移動次數即可。
4 代碼
1#include <iostream> 2using namespace std; 3const int maxn=10000+5;//數組大小比數據範圍稍大 4int a[maxn]; 5int main() 6{ 7 int n; 8 int ans=0,sum=0,t=0;//ans表示移動次數,t表示要移動的牌數 9 cin>>n; 10 for(int i=0;i<n;i++)//輸入數據 11 { 12 cin>>a[i]; 13 sum+=a[i]; 14 } 15 int avg=sum/n;//求平均值 16 for(int i=0;i<n-1;i++)//遍歷每個牌堆(到最後一堆牌數一定等於平均值) 17 { 18 if(a[i]+t!=avg)//如果這個牌堆收到移動過來的牌後牌數不等於平均值,就需要移動 19 { 20 t=a[i]+t-avg;//計算移動的牌數,或正或負。 21 ans++;//移動移動次數加一 22 } 23 else 24 { 25 t=0;//不用移動就是移動0張且次數不變 26 } 27 28 } 29 cout<<ans<<endl; 30 return 0; 31}
以上就是用貪心思想求解均分紙牌問題的整個過程,感謝老鐵:淡雅刺影的供稿,你們看懂了嗎?