1. 程式人生 > >#5:你的背包——6

#5:你的背包——6

long none line return 自然數 tchar int char rime

自然數拆分,完全背包

技術分享圖片
 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\nBest jury has value %d for prosecution and value %d for defence:\n", ++kase, val1, val2); 64 irep(i, p, 1) printf(" %d", ans[i]); 65 puts("\n"); 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\n", 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\n", f[n&1][0]);
49     return 0;    
50 }
View Code

#5:你的背包——6