现在的位置: 首页 > 综合 > 正文

UVa #12563 Jin Ge Jin Qu hao (例题9-5)

2018年10月14日 ⁄ 综合 ⁄ 共 1940字 ⁄ 字号 评论关闭

因为同时有两个要求(数量最多、数量相同时长度最长),所以要维护两个数组。

因为T一定小于所有歌的长度的和,所以T上限是9678。不过如果T真的有10^9那么大应该如何处理?动态规划还适用吗?

我尝试用记忆化搜索WA了,很奇怪。换成递推就直接过了。

递推时,因为歌曲的出现顺序并不重要,所以在读取数据的时候,下标可以逆序从N-1到0,这样可以实现边读入边处理。如果歌曲顺序有要求的话,也可以换一下状态的定义,改为“dp(i,j)表示在时间 j 内唱前 i 首歌,最多可以唱多少首”(原本是 i 到N-1),和书中的0-1背包一样。

因为不需要打印解,滚动数组也可以。加上边读入边处理的优化,速度会稍微快一些。要注意内层循环的顺序。

滚动数组:Run Time: 0.039s

#define UVa  "LT9-5.12563.cpp"		//Jin Ge Jin Qu hao
char fileIn[30] = UVa, fileOut[30] = UVa;

#include<cstring>
#include<cstdio>
#include<algorithm>

using namespace std;

//Global Variables. Reset upon Each Case!
const int maxn = 50 + 10, maxt = 10000;     //180 * n + 678 <= 180*50+678 = 9678 < 10000
int songs[maxn];
int dp[maxt];
int len[maxt];
int N, T;
/////

int main() {
    int K;
    scanf("%d", &K);
    for(int kase = 1; kase <= K; kase ++) {
        scanf("%d%d", &N, &T);
        for(int i = 0; i < maxt; i ++) {
            dp[i] = 1;
            len[i] = 678;
        }
        int song, ans = -1, anslen = -1;
        for(int i = 0; i < N; i ++) {
            scanf("%d", &song);
            for(int j = T; j >= 0; j --) {
                if(j > song) {
                    int tmp = dp[j - song] + 1;
                    if(tmp > dp[j]) {
                        dp[j] = tmp;
                        len[j] = len[j - song] + song;
                    }
                    else if(tmp == dp[j])
                        len[j] = max(len[j], len[j - song] + song);
                }
                if(ans < dp[j]) {
                    ans = dp[j];
                    anslen = len[j];
                }
                else if(ans == dp[j])
                    anslen = max(anslen, len[j]);
            }
        }
        printf("Case %d: %d %d\n", kase, ans, anslen);
    }
    return 0;
}

普通递推:Run Time: 0.053

#define UVa  "LT9-5.12563.cpp"		//Jin Ge Jin Qu hao
char fileIn[30] = UVa, fileOut[30] = UVa;

#include<cstring>
#include<cstdio>
#include<algorithm>

using namespace std;

//Global Variables. Reset upon Each Case!
const int maxn = 50 + 10, maxt = 10000;     //180 * n + 678 <= 180*50+678 = 9678 < 10000
int songs[maxn];
int dp[maxn][maxt];
int len[maxn][maxt];
int N, T;
/////

int main() {
    int K;
    scanf("%d", &K);
    for(int kase = 1; kase <= K; kase ++) {
        scanf("%d%d", &N, &T);
 
        for(int i = 0; i < N; i ++) scanf("%d", &songs[i]);

        for(int i = 0; i < maxt; i ++) {
            dp[N][i] = 1;
            len[N][i] = 678;
        }
        for(int i = N - 1; i >= 0; i --) {
            for(int j = 0; j <= T; j ++) {
                dp[i][j] = dp[i+1][j];
                len[i][j] = len[i+1][j];
                if(j > songs[i]) {
                    int tmp = dp[i+1][j - songs[i]] + 1;
                    if(tmp > dp[i][j]) {
                        dp[i][j] = tmp;
                        len[i][j] = len[i+1][j - songs[i]] + songs[i];
                    }
                    else if(tmp == dp[i][j])
                        len[i][j] = max(len[i][j], len[i+1][j - songs[i]] + songs[i]);
                }
            }
        }
        printf("Case %d: %d %d\n", kase, dp[0][T], len[0][T]);
    }
    return 0;
}



抱歉!评论已关闭.