Raucous Rockers

来源:互联网 发布:最新手游服务端源码 编辑:程序博客网 时间:2024/05/19 07:08

题意:有N首歌(按照写作的顺序给出每首歌的时间),还有M个压缩碟,每个压缩碟能容纳T分钟的歌曲。歌曲不允许跨碟存储,而且要按照写作顺序存储。求这M个压缩碟最多可以存储多少首歌?

解题思路

  1. DP问题,开始不知到怎么做,于是参考了USACO中Skywalker的“一种时间复杂度O(n^2)的DP算法”(http://www.nocow.cn/index.php/USACO/rockers)
  2. f(i, j) = (a, b)代表在最优情况下,从前i首歌曲中存储j首歌曲后,已经占用a个压缩碟,且第a+1个压缩碟中已经占据b时间
  3. 边界条件j=0时,f(i, j) = (0, 0)
  4. 滚雪球的过程:f(i, j) = min(f(i - 1, j), f(i - 1, j - 1) + cost_of_song(i))。也就是将f(i, j)分为不包括第i首歌以及包括第i首歌两种情况。求最小值要比较(a, b)这个数对,首先比较a,在a相等的情况下再比较b
  5. 最后从N到0遍历f[N][j],找到第一个满足条件的数对(a, b)那么对应的j就是最终的答案

代码

/*ID: zc.rene1LANG: CPROG: rockers*/#include<stdio.h>#include<stdlib.h>#include<string.h>#define MAX 20int main(void){    FILE *fin, *fout;    int N, T, M;    int songs[MAX + 1];    int f[MAX + 1][MAX + 1][2];    int i, j, temp_m, temp_t;    fin = fopen("rockers.in", "r");    fout = fopen("rockers.out", "w");    /*get the input*/    fscanf(fin, "%d %d %d", &N, &T, &M);    for (i=1; i<=N; i++)    {fscanf(fin, "%d", &songs[i]);    }    /*begin DP*/    for (i=0; i<=N; i++)    {for (j=0; j<=N; j++){    if (j == 0)    {memset(f[i][j], 0, 2 * sizeof(int));    }    else    {f[i][j][0] = M;f[i][j][1] = T;    }}    }    for (i=1; i<=N; i++)    {for (j=1; j<=i; j++){    temp_m = f[i-1][j-1][0];    temp_t = f[i-1][j-1][1];    if (songs[i] > T)    {temp_m = M;temp_t = T;    }    else    {if ((temp_t + songs[i]) <= T){    temp_t += songs[i];}else{    temp_m++;    temp_t = songs[i];}    }    if (f[i-1][j][0] < temp_m)    {memcpy(f[i][j], f[i-1][j], 2 * sizeof(int));    }    else if (f[i-1][j][0] == temp_m)    {if (f[i-1][j][1] > temp_t){    f[i][j][0] = temp_m;    f[i][j][1] = temp_t;}else{    memcpy(f[i][j], f[i-1][j], 2 * sizeof(int));}    }    else    {f[i][j][0] = temp_m;f[i][j][1] = temp_t;    }}    }        for (j=N; j>=0; j--)    {if (f[N][j][0] < M){    fprintf(fout, "%d\n", j);    break;}    }    if (j == -1)    {fprintf(fout, "0\n");    }        return 0;}