参考文章:http://blog.csdn.net/u013480600/article/details/40376143
自己写的AC代码如下:
#include
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
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[n][t0-1].n+1 << " " << F[n][t0-1].len +678 << endl;
}
return 0;
}
#include
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[n][t0-1].n+1 << " " << F[n][t0-1].len +678 << endl;
}
return 0;
}
#include
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[n][t0-1].n+1 << " " << F[n][t0-1].len +678 << endl;
}
return 0;
}
#include
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
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;
}