修補圍籬

題目說明

有一個農場有寬度為 nn 的圍籬,每個圍籬都有各自的高度,有些圍籬被吹斷了(高度為 00 表示被吹斷了),農場主人要來修補這些圍籬,但他忘記這些壞掉的圍籬原本高度是多少,為了減少成本,他會取斷掉的圍籬位置相鄰左邊和右邊較小的那個高度填上去,求需要多少成本。題目保證不會有兩個相鄰的吹斷圍籬,而穿斷的圍籬有可能位在邊界。

解題思路

讀完題目之後,我們可以先整理出這個策略:

  • 我們需要先宣告一個陣列來儲存圍籬的高度
  • 接著掃過整個陣列
    • 如果發現圍籬高度為 00,則取左右兩邊較小的高度加入答案
  • 最後輸出答案

解題過程

首先在 main 函式中宣告一個大小為 105105 的陣列 h 來儲存圍籬的高度:

int h[105];

然後,進入 main 函式,我們需要先宣告一個變數 nn 來儲存有幾個圍籬並且輸入變數 nn,初始化一個 ansans 變數來儲存我們的答案:

int n = 0, ans = 0;
cin >> n;

依序輸入 nn 個圍籬的高度,這裡要使用到 for 迴圈來幫助我們:

for (int i = 1; i <= n; i++) {
    cin >> h[i];
}

接著,我們要掃過整個陣列,當發現高度為 00 就取左右邊比較小的加入答案(這邊我們使用前面章節提到的 數學函式 來把程式寫的更精簡):

for (int i = 1; i <= n; i++) {
    // 如果找到被吹斷的圍籬
    if (h[i] == 0) {
        // 取左右兩邊較小的高度加入答案
        ans += min(h[i - 1], h[i + 1]);
    }
}

如果有仔細思考的話,這邊應該會注意到上面的程式碼其實會出一點小問題,原因是當我們掃到邊界的時候,我們對左右兩邊取小的那個一定會取到 00(原因是我們沒有把值輸入進去,且 main 外的陣列預設值為 00),這樣會造成我們沒算到邊界的情況。

有一個比較巧妙的方法是把第 00 個和第 n+1n + 1 個圍籬的高度先設為一個更大的數,這樣就可以避免這個問題:

// 這邊用 101 是因為題目保證圍籬高度不會超過 100
h[0] = 101;
h[n + 1] = 101;

// 掃過整個陣列並且計算答案
for (int i = 1; i <= n; i++) {
    if (h[i] == 0) {
        ans += min(h[i - 1], h[i + 1]);
    }
}

最後再將答案輸出即可:

cout << ans;

完整程式碼如下:

#include <bits/stdc++.h>
using namespace std;

int h[105];

int main(){
    int n = 0,ans = 0;
    cin >> n;
    h[0] = 101;
    h[n + 1] = 101;
    for (int i = 1; i <= n; i++){
        cin >> h[i];
    }
    // 掃過整個陣列並且計算答案
    for (int i = 1; i <= n; i++) {
        // 如果找到被吹斷的圍籬
        if (h[i] == 0){
            // 取左右兩邊較小的高度加入答案
            ans += min(h[i - 1], h[i + 1]);
        }
    }
    cout << ans;
}