USACO算法系列四——inflate

    题目:http://www.nocow.cn/index.php/Translate:USACO/inflate

    这道题目类似于算法与数据结构当中的01背包问题,只是这里的物品有数量的问题。但是还是可以用动态规划解决问题。

    我们假设f[type][minute]表示对前面type种题目在minute分钟下最大的得分情况。用struct Problem{ int point; int minute;}结构体数组表示题目类型和分数。则

    当type>1时,f[type][minute] = max(k * problem[type-1].point + f[type-1][minute - k * problem[type-1].minute]) ;(k属于0到minute / problem[type].minute之间)

    当type=1时,f[type][minute] = minute / problem[type].minute * problem[type].point;

    抽象出动态规模模型以后,代码就很容易实现了,代码如下:

#include <iostream> #include <fstream> #define MAX 10001 using namespace std; int m,n; struct Problem { int point; int minute; }; Problem * problem; int record[MAX][MAX];//备忘录表 int inflate(int index, int minute) { if (index == n-1) { int t = minute / problem[index].minute; record[index][minute] = problem[index].point * t; return record[index][minute]; } else { int max = 0; int m = minute; for (int i=0; m>=0; i ++) { int p = i * problem[index].point; if (record[index+1][m] != -1) { p += record[index+1][m]; } else { p += inflate(index +1,m); } max = max<p ? p : max; m = m- problem[index].minute; } record[index][minute] = max; return record[index][minute]; } } int main() { ifstream fin("inflate.in"); ofstream fout("inflate.out"); //输入数据 fin >> m >> n; problem = new Problem[n]; for (int i=0; i < n; i ++) { fin >> problem[i].point >> problem[i].minute; } //初始化 for (int i =0; i < n; i ++) { for (int j=0; j <= m; j ++) { record[i][j] = -1; } } int result = inflate(0,m); fout << result << endl; fin.close(); fout.close(); return 0; }

    然而遗憾的是,为了便于更快的得出答案,我们使用了一个二维的数组进行数据的存储,但是发现这个二维数组的利用率并不是很高,而且很快就超过了USACO的空间要求了。

     在01背包问题中有一个空间优化的方法,我们可以试一试,重新建立模型。这一块我虽然能够理解,但是却讲不太清楚。可能会存在很多歧义,希望大家自己批判性的看,自己看代码,或者详细复习一下01背包问题的空间优化方法,斟酌其中的含义。

     我们声明一个数组,f[minute],把每个单元想象成可以重复利用的小房间,房间的容量就是minute,如f[100]表示容量为100的小房间,他的值表示在房间下最大分数,因此初始值为0,那么对于一个m2 = m1 + problem[i].minute的空间,那么他的最大分数可以是 利用problem[i].minute装问题i,然后将m1空间充分利用的最大分数f[m1],或者不利用problem[i].minute的时间解决问题i,而是用这些时间解决前面i-1个问题的最大值,也就是上一次递归保存的f[m2]。因此递推的关键是每次迭代问题,空间都要从小开始往上递推。

     因此,对于每次循环,f[minute] = max(f[minute] , f[minute - problem[i].minute] + problem[i].point) 。

     觉得还是没讲清楚。直接上代码吧。

#include <iostream> #include <fstream> #define MAX 10001 using namespace std; int m,n; struct Problem { int point; int minute; }; Problem * problem; int record[MAX] = {0};//备忘录表 int main() { ifstream fin("inflate.in"); ofstream fout("inflate.out"); //输入数据 fin >> m >> n; problem = new Problem[n]; for (int i=0; i < n; i ++) { fin >> problem[i].point >> problem[i].minute; } for (int i=0; i <n; i ++) { for (int j=problem[i].minute; j <= m; j ++ ) { record[j] = max(record[j],record[j-problem[i].minute] + problem[i].point); }//end for j }//end for i fout << record[m] << endl; fin.close(); fout.close(); return 0; }

你可能感兴趣的:(USACO算法系列四——inflate)