UVa12563_劲歌金曲(动态规划_01背包变形)
2015-12-19 17:23
302 查看
参考文章:http://blog.csdn.net/u013480600/article/details/40376143
自己写的AC代码如下:
初始版本:
优化版本1:整理了判断条件
优化版本2:边读入边计算
优化版本3:使用滚动数组优化空间
优化版本4:边界时间
自己写的AC代码如下:
#include<bits/stdc++.h> using namespace std; const int maxt = 50 * 3 * 60 + 5; typedef struct { int n; int len; }Node; Node F[maxt]; Node best(Node& x, Node& y){ if(x.n < y.n) return y; else if(x.n == y.n && x.len<=y.len) return y; else return x; } int main() { int T; scanf("%d", &T); int count = 0; while(T--) { int n, t0, t; scanf("%d%d", &n, &t0); memset(F, 0, sizeof(F)); int max_t; max_t = min(maxt, t0); for(int i = 1; i <= n; i++) { scanf("%d", &t); for(int j = max_t-1; j>= 0; j--) { if(i==1){ F[j].n = 0; F[j].len = 0; }else { F[j] = F[j]; } if(j >= t) { Node tmp; tmp.n = F[j-t].n + 1; tmp.len = F[j-t].len + t; F[j] = best(F[j], tmp); } } } printf("Case %d: %d %d\n", ++count, F[t0-1].n+1, F[t0-1].len+678); } return 0; }
初始版本:
#include<bits/stdc++.h> using namespace std; //状态F[i][j]:前i首歌曲所达到的最优状态 //这个最优状态包括两个小的最优状态 //1.最大歌曲数 、 2.最长歌曲时间 //状态转移方程:F[i][j] = 最优(F[i-1][j], F[i-1][j-t[i]] + t[i]); const int maxn = 50 + 5; const int maxt = 50 * 3 * 60; int t[maxn];//每首歌曲时间 typedef struct {//状态节点定义 int n;//1.最大歌曲数 int len;//2.最长歌曲时间 }Node; Node F[maxn][maxt]; //状态节点 Node best(Node& x, Node& y){ if(x.n < y.n) return y; else if(x.n == y.n && x.len<=y.len) return y; else return x; } int main() { int T; cin >> T; int count = 0; while(T--) { int n, t0; cin >> n >> t0; //F数组的初始化; memset(F, 0, sizeof(F)); for(int i = 0; i <= n; i++) { cin >> t[i]; } for(int i = 1; i <= n; i++) { for(int j = 1; j <= t0-1; j++) { if(i==1){ F[i][j].n = 0; F[i][j].len = 0; }else { F[i][j] = F[i-1][j]; } Node tmp; if(j >= t[i]) { tmp.n = F[i-1][j-t[i]].n + 1; tmp.len = F[i-1][j-t[i]].len + t[i]; } if(j >= t[i] && tmp.len <= (t0-1)) F[i][j] = best(F[i][j], tmp);//两个子状态的比较 //cout << "F["<< i <<"]["<< j <<"] = " << F[i][j].len << endl; //打印状态 } } cout << "Case " << ++count << ": " << F [t0-1].n+1 << " " << F [t0-1].len +678 << endl; } return 0; }
优化版本1:整理了判断条件
#include<bits/stdc++.h> using namespace std; //状态F[i][j]:前i首歌曲所达到的最优状态 //这个最优状态包括两个小的最优状态 //1.最大歌曲数 、 2.最长歌曲时间 //状态转移方程:F[i][j] = 最优(F[i-1][j], F[i-1][j-t[i]] + t[i]); const int maxn = 50 + 5; const int maxt = 50 * 3 * 60; int t[maxn];//每首歌曲时间 typedef struct {//状态节点定义 int n;//1.最大歌曲数 int len;//2.最长歌曲时间 }Node; Node F[maxn][maxt]; //状态节点 Node best(Node& x, Node& y){ if(x.n < y.n) return y; //先要保证歌曲数最大的情况下 ,再保证总时间最长 else if(x.n == y.n && x.len<=y.len) return y; else return x; } int main() { int T; cin >> T; int count = 0; while(T--) { int n, t0; cin >> n >> t0; memset(F, 0, sizeof(F)); for(int i = 1; i <= n; i++) { cin >> t[i];//输入可以放在这里 能够这样写取决于状态的设定(状态要求i是顺序枚举) for(int j = 0; j <= t0-1; j++) { if(i==1){ //边界一定要记得处理 F[i][j].n = 0; F[i][j].len = 0; }else { F[i][j] = F[i-1][j]; } if(j >= t[i]) { Node tmp; tmp.n = F[i-1][j-t[i]].n + 1; tmp.len = F[i-1][j-t[i]].len + t[i]; F[i][j] = best(F[i][j], tmp);//两个子状态的比较 } // tmp.len <= (t0-1)这个条件的判断实际上是不需要的,之所以前面一个代码会加上, // 就是因为对自己定义的这个状态还不是很清楚 // 临时状态tmp 是在之前.前i-1首歌曲在j-t[i]的时间内达到的最优状态F[i-1][j-t[i]]的基础上 // 再加上i这首歌曲的时间t[i]所达到的新状态,也就是说tmp状态就是F[i][j]的一种决策(增加第i首歌曲),而 // F[i][j]的另一种决策自然就是F[i-1][j](即不增加第i首歌曲),所以无论是哪一个tmp,他的时间即 // tmp.len一直都是j, j的变化范围是1~(t0-1), 自然就不会超过t0-1这个值,所以 // tmp.len <= (t0-1)这个判断条件是多余的。 // cout << "F["<< i <<"]["<< j <<"] = " << F[i][j].len << endl; //打印状态 } } cout << "Case " << ++count << ": " << F [t0-1].n+1 << " " << F [t0-1].len +678 << endl; } return 0; }
优化版本2:边读入边计算
#include<bits/stdc++.h> using namespace std; //状态F[i][j]:前i首歌曲所达到的最优状态 //这个最优状态包括两个小的最优状态 //1.最大歌曲数 、 2.最长歌曲时间 //状态转移方程:F[i][j] = 最优(F[i-1][j], F[i-1][j-t] + t[i]); const int maxn = 50 + 5; const int maxt = 50 * 3 * 60 + 5; //顺序读入 边读边计算使得可以不要t[maxn]这个数组,所以可以直接用t代替当前第i首歌曲的时间 typedef struct {//状态节点定义 int n;//1.最大歌曲数 int len;//2.最长歌曲时间 }Node; Node F[maxn][maxt]; //状态节点 Node best(Node& x, Node& y){ if(x.n < y.n) return y; //先要保证歌曲数最大的情况下 ,再保证总时间最长 else if(x.n == y.n && x.len<=y.len) return y; else return x; } int main() { int T; cin >> T; int count = 0; while(T--) { int n, t0, t; cin >> n >> t0; memset(F, 0, sizeof(F)); for(int i = 1; i <= n; i++) { cin >> t;//输入可以放在这里 能够这样写取决于状态的设定(状态要求使得i是顺序枚举) for(int j = 0; j <= t0-1; j++) { if(i==1){ //边界一定要记得处理 F[i][j].n = 0; F[i][j].len = 0; }else { F[i][j] = F[i-1][j]; //无论如何,先使当前状态(F[i][j])等于相同时间j下不加上当前这首歌(i)的最优状态F[i-1][j] } if(j >= t) { Node tmp; tmp.n = F[i-1][j-t].n + 1; tmp.len = F[i-1][j-t].len + t; F[i][j] = best(F[i][j], tmp);//两个子状态的比较 } } } cout << "Case " << ++count << ": " << F [t0-1].n+1 << " " << F [t0-1].len +678 << endl; } return 0; }
优化版本3:使用滚动数组优化空间
#include<bits/stdc++.h> using namespace std; //状态F[j]:前i首歌曲所达到的最优状态 //这个最优状态包括两个小的最优状态 //1.最大歌曲数 、 2.最长歌曲时间 //状态转移方程:F[j] = 最优(F[j], F[i-1][j-t] + t); //F数组是从上到下、从右往左计算的。在计算F[i][j]之前,F[j]中保存的就是F[i-1][j]的值,所以可以把它写成一维 //参考紫书p273图(9-6) 这个就是滚动数组,优化了空间 注意使用滚动数组时 j一定要逆序枚举 不然后面的F元素 //会因为前面已经更新的F元素而再次更新 (倒序就不会发生这样的情况),从而发生错误。!!! //const int maxn = 50 + 5;F变成一维数组 ,这个也就省略了 const int maxt = 50 * 3 * 60 + 5; //顺序读入 边读边计算使得可以不要t[maxn]这个数组,所以可以直接用t代替当前第i首歌曲的时间 typedef struct {//状态节点定义 int n;//1.最大歌曲数 int len;//2.最长歌曲时间 }Node; Node F[maxt]; //状态节点 Node best(Node& x, Node& y){ if(x.n < y.n) return y; //先要保证歌曲数最大的情况下 ,再保证总时间最长 else if(x.n == y.n && x.len<=y.len) return y; else return x; } int main() { int T; cin >> T; int count = 0; while(T--) { int n, t0, t; cin >> n >> t0; //F数组的初始化; memset(F, 0, sizeof(F)); //这一句其实也可以不要 想一想这个数组的更新过程就知道了 //不过最好还是写上,以区别每一组测试数组就清空一下F状态数组 for(int i = 1; i <= n; i++) { cin >> t;//输入可以放在这里 能够这样写取决于状态的设定(状态要求使得i是顺序枚举) for(int j = t0-1; j>= 0; j--) { if(i==1){ //边界一定要记得处理 F[j].n = 0; F[j].len = 0; }else { F[j] = F[j]; //无论如何,先使当前状态(F[i][j])等于相同时间j下不加上当前这首歌(i)的最优状态F[i-1][j] } if(j >= t) { Node tmp; tmp.n = F[j-t].n + 1; tmp.len = F[j-t].len + t; F[j] = best(F[j], tmp);//两个子状态的比较 } } } cout << "Case " << ++count << ": " << F[t0-1].n+1 << " " << F[t0-1].len +678 << endl; } return 0; }
优化版本4:边界时间
//涉及结构体整体赋值,用C++写更方便 #include<bits/stdc++.h> using namespace std; const int maxt = 50 * 3 * 60 + 5; typedef struct { int n; int len; }Node; Node F[maxt]; Node best(Node& x, Node& y){ if(x.n < y.n) return y; else if(x.n == y.n && x.len<=y.len) return y; else return x; } int main() { int T; scanf("%d", &T); int count = 0; while(T--) { int n, t0, t; scanf("%d%d", &n, &t0); memset(F, 0, sizeof(F)); int max_t; max_t = min(maxt, t0); //两个时间 一个 是怎么都不会超过的maxt 一个是给出的时间t0 //说了不超过50首歌 且 每首不超过3分钟 而且每首最多只唱一遍 只要判maxt-1和t0-1中最小的那个作为j最值就行。 for(int i = 1; i <= n; i++) { scanf("%d", &t); for(int j = max_t-1; j>= 0; j--) { if(i==1){ F[j].n = 0; F[j].len = 0; }else { F[j] = F[j]; } if(j >= t) { Node tmp; tmp.n = F[j-t].n + 1; tmp.len = F[j-t].len + t; F[j] = best(F[j], tmp); } } } printf("Case %d: %d %d\n", ++count, F[t0-1].n+1, F[t0-1].len+678); } return 0; }
相关文章推荐
- iOS 跳转到appstore
- 机器学习知识体系
- 数据结构教程期末学习总结
- 值得推荐的C/C++框架和库
- 黑马程序员-OC-Foundation-NSArray
- 数据结构学期总结
- MyBatis模板化
- Delphi 7.0编写程序访问JAX-WS提供的WebService问题
- Mac下批量删除.DS_Store及.svn文件命令
- JavaScript中的 prototype 和 constructor
- 最佳日志实践
- openjudge heavy transportation
- 正则表达式
- UILabel 行间距
- 《ios—set方法的内存管理》
- 最后冲刺 我的项目 广商小助手
- Mac搭载git
- 认识反素数
- 简单树匹配(STM)及其应用举例
- 【【第16周-内部排序项目3—插入排序之希尔排序】】