洛谷P1031 均分紙牌

題目描述
有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)。

輸入輸出格式
輸入格式:
兩行第一行爲:N(N 堆紙牌,1≤N≤100)第二行爲:A1,A2,…,An​ (N堆紙牌,每堆紙牌初始數,1≤Ai≤10000)
輸出格式:
一行:即所有堆均達到相等時的最少移動次數。

輸入輸出樣例
輸入樣例#1:
4
9 8 17 6
輸出樣例#1:
3

思維題:
這道題我推了半天感覺很難啊,分了好幾種情況,又是找最大值,又是判斷左右區間,很亂,而且還理不清思路。
題解的意思是,先計算平均值,然後每個數都減去平均值,這樣得到的數列就是以0爲均值的數列,大於零代表比均值多的數量,小於零代表比均值少的數量。在拿的時候也不用去找多的看如何分給少的,直接從左至右把值往右加,因爲把少的拿給多的和把多的拿給少的是一樣的。注意前導零要排除,中間加到0的那一部不計步數。

代碼:

#include<iostream>
using namespace std;
//P1031 均分紙牌
int main()
{
 int N, ave, sum = 0, tmp = 0, ans = 0, a[10005];//N是堆數,ave是均值,sum用來計算總和,tmp用來存移動時加給下一個數的值,ans記錄移動次數,數組a存數
 cin >> N;
 for (int i = 0; i < N; i++)//輸入數據並計算總和
 {
  cin >> a[i];
  sum += a[i];
 }
 ave = sum / N;//計算均值
 for (int i = 0; i < N; i++)//每個值減去均值
 {
  a[i] -= ave;
 }
 tmp = 0;
 for (int i = 0; i < N; i++)//模擬計算步數
 {
  if (a[i] == 0 && tmp == 0)//如果有前導零,跳過
   continue;
  a[i] += tmp;//a[i]加上前一步傳過來的數
  tmp = a[i];//更新tmp爲當前剩餘的值
  if(tmp!=0)//如果剩餘爲0,說明前一個數加過來剛好補齊這一個數缺的/多的,就不用往後加0了;如果剩餘不爲零,就步數加一
   ans++;
 }
 cout << ans << endl;
 //system("pause");
 return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章