#5:你的背包——6
Posted alphawa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#5:你的背包——6相关的知识,希望对你有一定的参考价值。
自然数拆分,完全背包
1 #include <cstdio> 2 #define ll long long 3 #define mod 2147483648 4 #define rep(i, a, b) for (int i = a; i <= b; i++) 5 6 int n; 7 ll f[4005]; 8 9 int main() { 10 scanf("%d", &n); 11 f[0] = 1; 12 rep(i, 1, n) 13 rep(j, i, n) 14 f[j] = (f[j] + f[j-i]) % mod; 15 printf("%d", (f[n]-1+mod) % mod); 16 return 0; 17 }
POJ1015,自己实现果然要费时调试……按照题面对数据处理一下再背包。打印路径。
1 #include <cstdio> 2 #include <cstring> 3 #include <map> 4 using namespace std; 5 #define R(a) scanf("%d", &a) 6 #define rep(i, a, b) for (int i = a; i <= b; i++) 7 #define irep(i, a, b) for (int i = a; i >= b; i--) 8 #define init(a, b) memset(a, b, sizeof(a)) 9 10 const int maxn = 205; 11 int n, m, kase; 12 int a[maxn], b[maxn], t[maxn]; 13 int f[25][850], d[25][850]; 14 map<int, int> pre; 15 int ans[maxn], p, val1, val2; 16 17 void print(int j, int k, int i) { 18 ans[++p] = i; 19 val1 += a[i]; 20 val2 += b[i]; 21 int nxt = pre[i*1000000+j*10000+k]; 22 if (!nxt) return; 23 print(j-1, k-t[i], nxt); 24 } 25 26 int cmp(int a, int b) { 27 int t = f[m][a], p = f[m][b]; 28 if (t < 0 && p < 0) return -1; 29 if (t >= 0 && p >= 0) return t > p ? a : b; 30 if (t >= 0) return a; 31 return b; 32 } 33 34 int main() { 35 while (~scanf("%d%d", &n, &m) && n | m) { 36 rep(i, 1, n) { 37 R(a[i]); 38 R(b[i]); 39 t[i] = a[i] - b[i] + 20; 40 } 41 42 init(f, 0xcf); 43 f[0][0] = 0; 44 rep(i, 1, n) 45 irep(j, m, 1) 46 rep(k, t[i], 40*m) { 47 if (f[j-1][k-t[i]] >= 0 && f[j][k] < f[j-1][k-t[i]] + a[i] + b[i]) { 48 f[j][k] = f[j-1][k-t[i]] + a[i] + b[i]; 49 pre[i*1000000+j*10000+k] = d[j-1][k-t[i]]; 50 d[j][k] = i; 51 } 52 } 53 54 rep(i, 0, 20*m) { 55 int k = cmp(20*m-i, 20*m+i); 56 if (k >= 0) { 57 p = val1 = val2 = 0; 58 print(m, k, d[m][k]); 59 break; 60 } 61 } 62 63 printf("Jury #%d Best jury has value %d for prosecution and value %d for defence: ", ++kase, val1, val2); 64 irep(i, p, 1) printf(" %d", ans[i]); 65 puts(" "); 66 } 67 return 0; 68 }
POJ1742,按多重背包的思路贪心一下。
1 #include <cstdio> 2 #include <cstring> 3 #define maxm 100005 4 #define init(a, b) memset(a, b, sizeof(a)) 5 #define R(a) scanf("%d", &a) 6 #define W(a) printf("%d ", a) 7 #define rep(i, a, b) for (int i = a; i <= b; i++) 8 9 int n, m; 10 int a[101], c[101]; 11 int used[maxm]; 12 bool f[maxm]; 13 14 int main() { 15 while (R(n), R(m), n) { 16 init(f, 0); 17 f[0] = true; 18 rep(i, 1, n) R(a[i]); 19 rep(i, 1, n) R(c[i]); 20 rep(i, 1, n) { 21 rep(j, 0, m) used[j] = 0; 22 rep(j, a[i], m) { 23 if (!f[j] && f[j-a[i]] && used[j-a[i]] < c[i]) { 24 f[j] = true; 25 used[j] = used[j-a[i]] + 1; 26 } 27 } 28 } 29 30 int ans = 0; 31 rep(i, 1, m) ans += f[i]; 32 W(ans); 33 } 34 return 0; 35 }
BZOJ2287,退背包,可行方案数可以等于总数减去不可行方案数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define R(a) scanf("%d", &a) 4 #define rep(i, a, b) for (int i = a; i <= b; i++) 5 #define irep(i, a, b) for (int i = a; i >= b; i--) 6 7 int n, m; 8 int w[2005]; 9 int f[2005], g[2005]; 10 11 int main() { 12 R(n), R(m); 13 f[0] = 1; 14 rep(i, 1, n) { 15 R(w[i]); 16 irep(j, m, 0) 17 f[j] = (f[j] + f[j-w[i]]) % 10; 18 } 19 20 rep(i, 1, n) { 21 rep(j, 0, w[i]-1) g[j] = f[j]; 22 rep(j, w[i], m) g[j] = (f[j] - g[j-w[i]] + 10) % 10; 23 rep(j, 1, m) printf("%d", g[j]); 24 puts(""); 25 } 26 return 0; 27 }
BZOJ1025,把题目本质抽出来即和为n的拆分,然后难的一点是lcm方案数等价于各素数加和小于等于n的方案数。之后分组背包即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 5 int n; 6 ll f[1001]; 7 int primes[1001], t; 8 bool mark[1001]; 9 10 inline void Get_primes(int n) { 11 for (int i = 2; i <= n; i++) { 12 if (!mark[i]) { 13 primes[++t] = i; 14 } 15 for (int j = 1; j <= t && i*primes[j] <= n; j++) { 16 mark[i*primes[j]] = true; 17 if (i % primes[j] == 0) break; 18 } 19 } 20 } 21 22 inline ll dp(int n) { 23 f[0] = 1ll; 24 for (int i = 1; i <= t; i++) 25 for (int j = n; j >= primes[i]; j--) 26 for (int k = primes[i]; k <= j; k *= primes[i]) 27 f[j] += f[j-k]; 28 return accumulate(f, f+n+1, 0ll); 29 } 30 31 int main() { 32 scanf("%d", &n); 33 Get_primes(n); 34 printf("%lld", dp(n)); 35 return 0; 36 }
BZOJ4247,首先排序,之后才能dp。dp的状态转移不是单纯的01背包因为那样会T,一种写法是处理一下使得大于n的状态都归于n;我用的第二种但私以为网上题解在理解上有些错误。一是这样写以后f[i][j]的定义其实变了,不再是前i个剩j个挂钩而是剩>=j个挂钩;二是选择1个的原因不是只能选1,而是我们本来要取1~n里最大的,而这种写法前面的一定比后面的大所以取1就能保证正确性了。果然最后的输出也不必把f数组遍历一遍,因为0肯定是最大的,直接输出即可AC。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define maxn 2005 4 #define gc getchar() 5 #define R(a) a = readint() 6 #define init(a, b) memset(a, b, sizeof(a)) 7 #define rep(i, a, b) for (int i = a; i <= b; i++) 8 9 const int inf = 0xcfcfcfcf; 10 int n; 11 int f[2][maxn]; 12 struct node { 13 int a, b; 14 bool operator < (const node x) const { 15 return a > x.a; 16 } 17 }p[maxn]; 18 19 inline int readint() { 20 int x = 0, s = 1, c = gc; 21 while (c <= 32) c = gc; 22 if (c == ‘-‘) s = -1, c = gc; 23 for (; isdigit(c); c = gc) 24 x = x * 10 + c - 48; 25 return x * s; 26 } 27 28 int main() { 29 R(n); 30 rep(i, 1, n) { 31 R(p[i].a); 32 R(p[i].b); 33 } 34 35 sort(p+1, p+1+n); 36 init(f, 0xcf); 37 f[0][0] = f[0][1] = 0; 38 rep(i, 1, n) { 39 rep(j, 0, n) { 40 if (j >= p[i].a) { 41 f[i&1][j] = max(f[i-1&1][j], f[i-1&1][j+1-p[i].a] + p[i].b); 42 } else { 43 f[i&1][j] = max(f[i-1&1][j], f[i-1&1][1] + p[i].b); 44 } 45 } 46 } 47 48 printf("%d ", f[n&1][0]); 49 return 0; 50 }
以上是关于#5:你的背包——6的主要内容,如果未能解决你的问题,请参考以下文章
在一个无序整数数组中,找出连续增长片段最长的一段, 增长步长是1。Example: [3,2,4,5,6,1,9], 最长的是[4,5,6]