[USACO1.3] 修理牛棚 Barn Repair
題目描述
在一個月黑風高的暴風雨夜,Farmer John 的牛棚的屋頂、門被吹飛了 好在許多牛正在度假,所以牛棚沒有住滿。
牛棚一個緊挨著另一個被排成一行,牛就住在裡面過夜。有些牛棚裡有牛,有些沒有。 所有的牛棚有相同的寬度。 寬度為1
自門遺失以後,Farmer John 必須儘快在牛棚之前豎立起新的木板。他的新木材供應商將會供應他任何他想要的長度,但是吝嗇的供應商只能提供有限數目的木板。 Farmer John 想將他購買的木板總長度減到最少。
給出 \(m,s,c\),表示木板最大的數目、牛棚的總數、牛的總數;以及每頭牛所在牛棚的編號,請算出攔住所有有牛的牛棚所需木板的最小總長度。
輸入格式
一行三個整數 \(m,s,c\),意義如題目描述。
接下來 \(c\) 行,每行包含一個整數,表示牛所佔的牛棚的編號。
輸出格式
輸出一行一個整數,表示所需木板的最小總長度。
樣例 #1
樣例輸入 #1
4 50 18
3
4
6
8
14
15
16
17
21
25
26
27
30
31
40
41
42
43
樣例輸出 #1
25
提示
【資料範圍】
對於 \(100\%\) 的資料,\(1\le m \le 50\),\(1\le c \le s \le 200\)。
USACO Training Section 1.3
思路:
- 題目很多資訊,我們首先捋清楚題目的意思。s與解題無關,我們應該剔除沒用的資訊,供應商最多可以提供m塊板子,有c個牛棚中住了牛,我們需要對這c個牛棚進行修補,每個牛棚需要長度為1的板子,但是我們的總板子數目不超過m個,因此,當m<c時,我們需要對有些牛棚的板子進行延長,比如我們對編號為2,3的兩個牛棚,我們使用一塊長度為2的木板來修復它,直到我們使用的木板總數等於m為止。
- 我們可以有一個思路,先對每個有牛的牛棚進行分配一塊長度為1的木板,如果供應的木板總數≥牛的數量,那麼我們的答案就是c,每個牛棚分配一塊長度為1的木板即可,否則,我們就得使用連續的木板來修復多個牛棚。比如編號為3和8的木板,我們使用長度為6的木板修復,不過因為我們一開始每個牛棚一個分配了長度為1的木板,所以只需要在原來答案的基礎上加上8-3-1即可,就是4,所以說得數出它們之間隔了幾個牛棚。
- 由上面的思路,我們得對有牛的牛棚陣列a進行排序,並使用另外一個陣列d,用來表示a中相鄰元素之間所隔著的牛棚數量
- 先對牛棚陣列a排序,並給每一個牛棚分配一個長度為1的木板:
for (int i = 1; i <= c; i++) cin >> a[i];
//先給每個有牛的牛棚分配一塊木板,如果最大木板數量不夠用的話,就得
//將某些木板連起來了。
int ans = c;
sort(a + 1, a + 1 + c);
- 然後,我們計算出a中相鄰元素的牛棚的數量,並對d陣列排序
for (int i = 2; i <= c; i++) d[i - 1] = a[i] - a[i - 1] - 1;
//d陣列總共有c-1個元素
sort(d + 1, d + c);
- 如果m<c的話,我們就每次選擇d陣列中最小的那個元素,因為它們之間相隔的木板數目最少,我們所需要付出的木板長度代價越低,這就是貪心思想所對應的區域性最優解。以往下去,我們使用的木板長度肯定是最少的,最終得到全域性最優解。
程式碼:
#include<iostream>
using namespace std;
#include<algorithm>
int a[205]; //作為有牛的牛棚的編號
int d[205]; //作為相鄰兩個牛棚之間間隔的牛棚的數量
int m, s, c;
int main()
{
cin >> m >> s >> c;
for (int i = 1; i <= c; i++) cin >> a[i];
//先給每個有牛的牛棚分配一塊木板,如果最大木板數量不夠用的話,就得
//將某些木板連起來了。
int ans = c;
sort(a + 1, a + 1 + c);
for (int i = 2; i <= c; i++) d[i - 1] = a[i] - a[i - 1] - 1;
sort(d + 1, d + c);
//如果最多提供的板子數量小於牛的數量,這時候就不能每頭有牛的牛棚都分配板子了,就得將某些牛棚的板子連起來。
if (m < c) {
//d陣列總共有c-m個元素,因為有c頭牛,最多提供m塊板子
//我們每次貪心的選擇相隔牛棚數最少的牛棚,這樣我們的代價越低,得到的結果越小,
for (int i = 1; i <= c - m; i++) ans += d[i];
}
cout << ans << endl;
return 0;
}
總結與思考
- 做資訊學競賽的題目,我們最重要的能力就是快速閱讀有用資訊的能力,並建立出自己的模型,或者是畫出對應的草圖,然後在草稿紙上推演出對應的數學關係,最後用程式碼表示出來