标签:
题目描述:
编号为0~n-1的n个位置上分别有价值为w[0]~w[n-1]的n个物品,现在要选出一些物品,使得获得的价值最大,约束条件是:任意连续的m个物品中选取的物品数量不超过q。其中n<=1000, 2<=m<=10, 1<=q<=m, w[i]<=100.
算法分析:
状态定义:
dp[i][s]表示:解决了物品0~i的选取问题,物品i-m+1, i-m+2, ..., i 的选取状态为s时,所获得的最大价值, 其中s的第0, 1, ..., m-1位分别指示物品i-m+1, i-m+2, ..., i的选取情况,对应位为1表示选取,为0表示不选取。
状态转移:
1.如果bitcnt(s)>q, 那么由s不可能转移出任何有效状态.
2.如果bitcnt(s)<=q, 那么此时分为两种情况(设下一状态为ns):
a.当不选取下一个物品时,ns=s>>1, 有转移方程:dp[i+1][ns] = max(dp[i+1][ns], dp[i][s]);
b.当选取下一个物品时,ns=(s>>1)+(1<<(m-1)), 在bitcnt(ns)<=q的条件下,有转移方程:dp[i+1][ns] = max(dp[i+1][ns], dp[i][s]+w[i+1]).
我的代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 #define MAXN 1100 6 7 int w[MAXN], dp[MAXN][MAXN]; 8 9 int bitcnt(int x) 10 { 11 int cnt = 0; 12 while(x) 13 { 14 if(x&1) ++cnt; 15 x = x>>1; 16 } 17 return cnt; 18 } 19 20 int main() 21 { 22 int n, m, q, ans; 23 while(scanf("%d%d%d", &n, &m, &q)!=EOF) 24 { 25 for(int i=0; i<n; ++i) 26 scanf("%d", &w[i]); 27 ans = 0; 28 if(n<m) 29 { 30 for(int s=0; s<(1<<n); ++s) 31 { 32 if(bitcnt(s)<=q) 33 { 34 int sum=0; 35 for(int j=0; j<n; ++j) if((s>>j)&1) sum += w[j]; 36 ans = max(ans, sum); 37 } 38 } 39 printf("%d\n", ans); 40 return 0; 41 } 42 43 memset(dp, 0, sizeof(dp)); 44 for(int s=0; s<(1<<m); ++s) 45 { 46 if(bitcnt(s)>q) continue; 47 int sum = 0; 48 for(int j=0; j<m; ++j) if((s>>j)&1) sum += w[j]; 49 dp[m-1][s] = sum; 50 } 51 for(int i=m-1; i<n-1; ++i) 52 { 53 for(int s=0; s<(1<<m); ++s) 54 { 55 int bcnt = bitcnt(s); 56 int ns; 57 if(bcnt>q) continue; 58 ns = s>>1; 59 dp[i+1][ns] = max(dp[i+1][ns], dp[i][s]); 60 ns = (s>>1)+(1<<(m-1)); 61 bcnt = bitcnt(ns); 62 if(bcnt>q) continue; 63 dp[i+1][ns] = max(dp[i+1][ns], dp[i][s]+w[i+1]); 64 } 65 } 66 for(int s=0; s<(1<<m); ++s) ans = max(ans, dp[n-1][s]); 67 printf("%d\n", ans); 68 } 69 return 0; 70 }
题目来源:http://hihocoder.com/problemset/problem/1044?sid=252822
标签:
原文地址:http://www.cnblogs.com/pczhou/p/4295514.html