UVA 12563 Jin Ge Jin Qu hao DP
题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4008
题目描述: 一共n首歌儿, 要求在t时间唱尽可能多的歌儿, 相同的歌儿的数量下总时长尽可能的长
解题思路: 设dp[i] 为正好唱i秒时唱的最多的歌儿的数量, 只有当i正好等于t[j]或者dp[i-t[j]]>=1 的时候才转移(因为i是正好唱了多少秒)
代码:
#include <iostream> #include <cstdio> #include <string> #include <vector> #include <map> #include <cstring> #include <iterator> #include <cmath> #include <algorithm> #include <stack> #include <deque> #include <map> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 const int maxn = 1e5; using namespace std; int dp[maxn]; // dp(i, j) 表示前 i 首歌儿正好唱 j s int t[100]; int main() { int T; scanf( "%d", &T ); for( int c = 1; c <= T; c++ ) { int n; int tot; scanf( "%d%d", &n, &tot ); for( int i = 1; i <= n; i++ ) { scanf( "%d", &t[i] ); } tot--; memset(dp, 0, sizeof(dp) ); int res = 0; for( int i = 1; i <= n; i++ ) { for( int j = tot; j >= t[i]; j-- ) { // if( i == 2 && j == 99 ) { // cout << dp[1][30] << endl; // // } if( dp[j-t[i]] >= 1 || j == t[i] ) { dp[j] = max( dp[j], dp[j-t[i]]+1 ); res = max( res, dp[j] ); } } } int i; for(i = tot; dp[i] != res; i--); if(res == 0) printf("Case %d: %d %d\n", c, 1, 678); else printf("Case %d: %d %d\n", c, 1 + res, i + 678); } return 0; }
思考: 一开始设计的状态是前 i 首歌儿 j 秒内唱的最多的数量, 后来发现这个只能把歌儿的数量求出来, 很难求最长时间, 然后我想既然是要求最长时间, 那我就改成前i 首歌儿 j 秒正好唱完的最多的数量, 发现状态没有办法转移, 因为dp[i][j] 没办法转移到 dp[k][j-t[i]] k是之前唱过的那首歌儿, 那么这样我就不关心前i首歌儿, 只关心正好唱了多少秒, 运用滚动数组就可以了......自己还是没办法将状态和题目的已知条件很好的联系起来......还是得经常做......
生日快乐
posted on 2017-08-05 12:22 FriskyPuppy 阅读(175) 评论(0) 编辑 收藏 举报