题目链接:
https://vjudge.net/problem/UVA-624
题目大意:
这道题给定一个时间上限,然后一个数字N,后面跟着N首歌的时间长度,要我们
求在规定时间w内每首歌都要完整的播放,最多能播放多少时间。一个比较典型的背包问题,
但是要标记出我们选出的歌曲的编号,然后按顺序输出他们的长度,最后输出求的的最长
播放时间。
思路:
这里要求输出路径(任一条即可),所以加了一个vis数组,如果在递推过程中,某一件需要拿的话,就标记下来,最终可以从后往前推导出具体路径,因为从后往前的话,判断当前是否被标记,未被标记x自减1,标记的话y就转移到y-w[i]的位置,这个过程和01背包正向推导过程完全相反。
推导过程中用栈记录结果
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stack> 6 using namespace std; 7 int T, n, m; 8 const int maxn = 10000 + 10; 9 int dp[25][maxn], w[25], vis[25][maxn]; 10 int main() 11 { 12 while(cin >> m >> n) 13 { 14 for(int i = 1; i <= n; i++)cin >> w[i]; 15 memset(dp, 0, sizeof(dp)); 16 memset(vis, 0, sizeof(vis)); 17 for(int i = 1; i <= n; i++) 18 { 19 for(int j = 0; j <= m; j++) 20 { 21 dp[i][j] = dp[i - 1][j]; 22 if(j >= w[i] && dp[i][j] < dp[i - 1][j - w[i]] + w[i]) 23 { 24 vis[i][j] = 1; 25 dp[i][j] = dp[i - 1][j - w[i]] + w[i]; 26 } 27 } 28 } 29 int sum = dp[n][m]; 30 int x = n, y = m; 31 stack<int>q; 32 while(sum) 33 { 34 if(vis[x][y])//从后往前存,由于vis数组只能从后一步推导出前一步 35 { 36 q.push(w[x]); 37 y -= w[x]; 38 sum -= w[x]; 39 } 40 x--; 41 } 42 while(!q.empty()) 43 { 44 cout<<q.top()<<" "; 45 q.pop(); 46 } 47 cout<<"sum:"<<dp[n][m]<<endl; 48 } 49 return 0; 50 }