USACO 1.4 Barn Repair 修理牛棚 (動態規劃)

DWAE86發表於2018-07-24

題目描述


在一個夜黑風高,下著暴風雨的夜晚,Farmer John的牛棚的屋頂、門被吹飛了。 好在許多牛正在度假,所以牛棚沒有住滿。 牛棚一個緊挨著另一個被排成一行,牛就住在裡面過夜。 有些牛棚裡有牛,有些沒有。 所有的牛棚有相同的寬度。 自門遺失以後,farmer John必須儘快在牛棚之前豎立起新的木板。 他的新木材供應商將會供應他任何他想要的長度,但是吝嗇的供應商只能提供有限數目的木板。 Farmer John想將他購買的木板總長度減到最少。

給出:可能買到的木板最大的數目M(1<= M<=50);牛棚的總數S(1<= S<=200); 牛棚裡牛的總數C(1 <= C <=S);和牛所在的牛棚的編號stall_number(1 <= stall_number <= S),計算攔住所有有牛的牛棚所需木板的最小總長度。 輸出所需木板的最小總長度作為答案。

 

樣例輸入&輸出


sample input

4 50 18
3 
4 
6 
8 
14
15 
16 
17 
21
25 
26 
27 
30 
31 
40 
41 
42 
43

sample output

25 

 

分析&反思


一道貪心非常簡單的題,用動歸做,小錯不斷。

分析:

d [ i ][ j ] 表示第頭牛到第j頭牛之間的距離。

f [ i ][ j ] 表示第j頭牛之前用i塊木板所需要的木板長度。

狀態轉移方程:f [ i ][ j ]  =  f[ i-1 ][ k-1 ]  +  d[ k ][ j ]   ( 1(可以是i)  <=  k  <=  j ) 

即第k頭牛和第j頭牛之間連上木板,加上第k-1頭牛之前的用i-1塊木板的最優情況。

反思:

1. 牛棚是一個塊不是一個點,本身有一個單位的長度 (實際考慮也非常合理)。

2. 給出的牛棚編號不一定是升序,像動歸或其他需要排序的題目,看好資料是不是按順序給。

3. 動歸好久沒做了,起點資料的初始化賦值要注意,該inf的inf,該-1的-1,該。。。。。。

4.雖說用的模板越多越好,但10頭牛也用不了50塊木板啊,不要想當然的以為木板數小於牛棚數。

 

程式碼


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;

const int inf = 1000000000;

int b[202], d[202][202], f[52][202];
int m, s, c;
int main () {
	
	freopen("barn1.in", "r", stdin);
	freopen("barn1.out", "w", stdout);
	
	cin >> m >> s >> c;
	m = min(m, c);
	for(int i = 1; i <= c; i++) cin >> b[i];
	
	sort(b+1, b+c+1);
	
	for(int i = 0; i <= 50; i++)
		for(int j = 0; j <= 200; j++) f[i][j] = inf;
	
	for(int i = 1; i <= c; i++)
		for(int j = 1; j <= c; j++) d[i][j] = b[j] - b[i] + 1;
		
	for(int i = 1; i <= c; i++) f[1][i] = b[i] - b[1] + 1;
		
	int ans = inf;	
	for(int i = 2; i <= m; i++)
		for(int j = 1; j <= c; j++) 
			for(int k = 1; k <= j; k++) 
				f[i][j] = min(f[i][j], f[i-1][k-1] + d[k][j]);
				
	
	cout << f[m][c] << endl;
	
	
	return 0;
	
}

 

備註


迴歸程式設計不久,有些問題是遺忘,有些問題是不熟練,有些問題沒搞懂過。。。

希望每天都能保持熱情 。

相關文章