#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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code

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 }
View Code
原文地址:https://www.cnblogs.com/AlphaWA/p/10350413.html