USACO 1.4 Barn Repair 修理牛棚 (动态规划)

题目描述


在一个夜黑风高,下着暴风雨的夜晚,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
#include
#include
#include
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;
	
}

 

备注


回归编程不久,有些问题是遗忘,有些问题是不熟练,有些问题没搞懂过。。。

希望每天都能保持热情 。

你可能感兴趣的:(动态规划,USACO)