题意:n首个按照给定顺序存在m张光盘里,每首歌有播放时间ti,并且只能完整的存在一张光盘里,问最多能存几首歌
分析:类似01背包和完全背包,每首歌可存可不存,存到下一张光盘的情况是当前存不下了。dp[i][j][k] 表示前i首歌,存在前j张光盘,光盘已存k时间时最多能存多少歌曲。状态转移方程:dp[i][j] = max (dp[i-1][j][k], dp[i-1][j][k-a[i]] + 1, dp[i-1][j-1][t] + 1) (分别代表不存,还能存,下一张存的状态)
收获:状态转移明确,常见的DP题
代码:
/************************************************ * Author :Running_Time * Created Time :2015-8-29 11:39:33 * File Name :UVA_473.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <deque> #include <stack> #include <list> #include <map> #include <set> #include <bitset> #include <cstdlib> #include <ctime> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 typedef long long ll; const int N = 1e3 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; int dp[900][120][120]; int a[N]; int main(void) { int T; scanf ("%d", &T); while (T--) { int n, m, t; scanf ("%d%d%d", &n, &t, &m); int cnt = 0; for (int i=1; i<=n; ++i) { int x; if (i == 1) scanf ("%d", &x); else scanf (", %d", &x); if (x <= t) a[++cnt] = x; } memset (dp, 0, sizeof (dp)); for (int i=1; i<=cnt; ++i) { for (int j=1; j<=m; ++j) { for (int k=0; k<=t; ++k) { dp[i][j][k] = dp[i-1][j][k]; if (k >= a[i]) { dp[i][j][k] = max (dp[i][j][k], dp[i-1][j][k-a[i]] + 1); dp[i][j][k] = max (dp[i][j][k], dp[i-1][j-1][t] + 1); } } } } printf ("%d ", dp[cnt][m][t]); if (T) puts (""); } return 0; }