周五我们做的杭电OJ上virtual contest,其中有一道《2012》,在problem中的题号为3602。比赛的时候我dp了一下,结果wrong了。发现这个题的题意和我之前做的USACO上Section 3.4 - Rockers 很像,Rockers的题意是从N首歌曲中选出最多数量的歌曲放到M张光盘上,每个光盘只能放T分钟的歌曲,每首歌曲只能在一张盘上,还有个要求就是选出的歌曲放到盘上的顺序必须和原歌曲的顺序相同。由于数据范围很小,规划思想是:用dp[i][j][k]表示前i首歌曲用j张盘,且最后一张盘用了k分钟,代码如下:
/* ID: morgan_xww LANG: C TASK: rockers */ #include <stdio.h> int Max(int a, int b) { return (a > b ? a : b); } int main() { freopen("rockers.in", "r", stdin); freopen("rockers.out", "w", stdout); int N, M, T, i, j, k; int a[21]; int dp[21][21][21]={0}; scanf("%d %d %d", &N, &T, &M); for (i=1; i<=N; i++) scanf("%d", &a[i]); for (i=1; i<=N; i++) for (j=1; j<=M; j++) for (k=1; k<=T; k++) { //不放第i首歌曲;不用第j个盘 dp[i][j][k] = Max(dp[i-1][j][k], dp[i][j-1][T]); if (a[i] < k) //把歌曲i插到第j个盘后面 dp[i][j][k] = Max(dp[i][j][k], dp[i-1][j][k-a[i]]+1); else if (a[i] == k) //把歌曲i插到一张新盘上 dp[i][j][k] = Max(dp[i][j][k], dp[i-1][j-1][T]+1); } printf("%d\n", dp[N][M][T]); exit(0); }
/** dp[i][j].nship 和 dp[i][j].left 分别表示 从前i个总统赚到j元钱所需要的ship数量和最后一个ship的剩余空间。 dp[i][j]的状态从dp[i-1][j] 和的 dp[i-1][j-v[i]] 转化而来。 **/ #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int n, m, k; int maxVal; struct CTY { int num; int value; } cty[101]; struct DP { int nship; //所需的飞船数量 int left; //最后一个飞船的剩余空间 bool tag; //标记该状态是否有效 void setValue(int a, int b, bool c) { nship = a; left = b; tag = c; } void add(DP d, CTY c) { if (d.tag == false) return ; if (d.left >= c.num) d.left -= c.num; else if (c.num <= k) { d.nship++; d.left = k-c.num; } else return ; if (d.nship > m) return ; if ( !tag || nship > d.nship || (nship == d.nship && left < d.left) ) setValue(d.nship, d.left, d.tag); } } dp[101][10001]; void solve() { memset(dp, 0, sizeof(dp)); for (int i=0; i<=n; i++) { dp[i][0].setValue(0, 0, true); } for (int i=1; i<=n; i++) { for (int j=1; j<=maxVal; j++) { if (dp[i-1][j].tag) dp[i][j] = dp[i-1][j]; if (j-cty[i].value >=0) dp[i][j].add(dp[i-1][j-cty[i].value], cty[i]); } } for (int j=maxVal; j>=0; j--) { if (dp[n][j].tag) { printf("%d\n", j); return ; } } } int main() { int nc; scanf("%d", &nc); while (nc--) { maxVal = 0; scanf("%d %d %d", &n, &m, &k); for (int i=1; i<=n; i++) { scanf("%d %d", &cty[i].num, &cty[i].value); cty[i].num++; maxVal += cty[i].value; } solve(); } return 0; }