均分紙牌(經典貪心)

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}

以上就是用貪心思想求解均分紙牌問題的整個過程,感謝老鐵:淡雅刺影的供稿,你們看懂了嗎?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章