for i=1..N for v=V..0 f[v]=max{f[v],f[v-c[i]]+w[i]}; 其中的f[v]=max{f[v],f[v-c[i]]}一句恰q当于我们的{ULEf[i][v]=max{f[i-1][v],f[i-1][v-c[i]]}Q因为现在的f[v-c[i]]q当于原来的f[i-1][v-c[i]]。如果将v的@环顺序从上面的逆序Ҏ序的话Q那么则成了f[i][v]由f[i][v-c[i]]推知Q与本题意不W,但它却是另一个重要的背包问题P02最L解决ҎQ故学习只用一l数l解01背包问题是十分必要的?/p>
for i=1..N for v=0..V f[v]=max{f[v],f[v-cost]+weight} 你会发现Q这个伪代码与P01的伪代码只有v的@环次序不同而已。ؓ什么这样一改就可行呢?首先xZ么P01中要按照v=V..0的逆序来@环。这是因保证Wiơ@环中的状态f[i][v]是由状态f[i-1][v-c[i]]递推而来。换句话_q正是ؓ了保证每件物品只选一ơ,保证在考虑“选入Wi件物?#8221;qg{略Ӟ依据的是一个绝无已l选入Wi件物品的子结果f[i-1][v-c[i]]。而现在完全背包的特点恰是每种物品可选无限gQ所以在考虑“加选一件第iU物?#8221;q种{略Ӟ却正需要一个可能已选入WiU物品的子结果f[i][v-c[i]]Q所以就可以q且必须采用v=0..V的顺序@环。这是q个单的E序Z成立的道理?/p>
#include <fstream> using namespace std; const unsigned int MAX_SUM = 1024; int n; unsigned long long int dyn[MAX_SUM]; ifstream fin ("subset.in"); ofstream fout ("subset.out"); int main() { fin >> n; fin.close(); int s = n*(n+1); if (s % 4) { fout << 0 << endl; fout.close (); return ; } s /= 4; int i, j; dyn [0] = 1; for (i = 1; i <= n; i++) for (j = s; j >= i; j--) dyn[j] += dyn[j-i]; fout << (dyn[s]/2) << endl; fout.close(); return 0; }
USACO 2.3 Longest Prefix 题目如下Q?br>在生物学中,一些生物的l构是用包含其要素的大写字母序列来表C的。生物学家对于把长的序列分解成较短的Q称之ؓ元素的)序列很感兴趣? 如果一个集?P 中的元素可以通过串联Q允讔R复;串联Q相当于 Pascal 中的 “+” q算W)l成一个序?S Q那么我们认为序?S 可以分解?P 中的元素。ƈ不是所有的元素都必d现。D个例子,序列 ABABACABAAB 可以分解Z面集合中的元素: {A, AB, BA, CA, BBC} 序列 S 的前?K 个字W称?S 中长度ؓ K 的前~。设计一个程序,输入一个元素集合以及一个大写字母序列,计算q个序列最长的前缀的长度? PROGRAM NAME: prefix INPUT FORMAT 输入数据的开头包?1..200 个元素(长度?1..10 Q组成的集合Q用q箋的以I格分开的字W串表示。字母全部是大写Q数据可能不止一行。元素集合结束的标志是一个只包含一?“.” 的行。集合中的元素没有重复。接着是大写字母序?S Q长度ؓ 1..200,000 Q用一行或者多行的字符串来表示Q每行不过 76 个字W。换行符q不是序?S 的一部分?br>SAMPLE INPUT (file prefix.in) A AB BA CA BBC . ABABACABAABC OUTPUT FORMAT 只有一行,输出一个整敎ͼ表示 S 能够分解?P 中元素的最长前~的长度?br>SAMPLE OUTPUT (file prefix.out) 11
CZE序如下Q?br> #include <stdio.h> /* maximum number of primitives */ #define MAXP 200 /* maximum length of a primitive */ #define MAXL 10 char prim[MAXP+1][MAXL+1]; /* primitives */ int nump; /* number of primitives */ int start[200001]; /* is this prefix of the sequence expressible? */ char data[200000]; /* the sequence */ int ndata; /* length of the sequence */ int main(int argc, char **argv) { FILE *fout, *fin; int best; int lv, lv2, lv3; if ((fin = fopen("prim.in", "r")) == NULL) { perror ("fopen fin"); exit(1); } if ((fout = fopen("prim.out", "w")) == NULL) { perror ("fopen fout"); exit(1); } /* read in primitives */ while (1) { fscanf (fin, "%s", prim[nump]); if (prim[nump][0] != '.') nump++; else break; } /* read in string, one line at a time */ ndata = 0; while (fscanf (fin, "%s", data+ndata) == 1) ndata += strlen(data+ndata); start[0] = 1; best = 0; for (lv = 0; lv < ndata; lv++) if (start[lv]) { /* for each expressible prefix */ best = lv; /* we found a longer expressible prefix! */ /* for each primitive, determine the the sequence starting at this location matches it */ for (lv2 = 0; lv2 < nump; lv2++) { for (lv3 = 0; lv + lv3 < ndata && prim[lv2][lv3] && prim[lv2][lv3] == data[lv+lv3]; lv3++) ; if (!prim[lv2][lv3]) /* it matched! */ start[lv + lv3] = 1; /* so the expanded prefix is also expressive */ } } /* see if the entire sequence is expressible */ if (start[ndata]) best = ndata; fprintf (fout, "%i\n", best); return 0; }
void add(bignum_t a, bignum_t b) { int c; /* carry */
c = 0; while (b || c) { a->val += c; if (b) a->val += b->val; /* if a->val is too large, we need to carry */ c = (a->val / 1000000); a->val = (a->val % 1000000); if (b) b = b->next; if (!a->next && (b || c)) { /* allocate if we need to */ a->next = get_big(); a = a->next; a->val = 0; a->next = NULL; } else a = a->next; } }
void out_num(FILE *f, bignum_t v) { if (v->next) { out_num(f, v->next); fprintf (f, "%06i", v->val); } else fprintf (f, "%i", v->val); } int main(int argc, char **argv) { FILE *fout, *fin; int lv, lv2; int c; int max; int l; bignum_t ans; if ((fin = fopen("buylow.in", "r")) == NULL) { perror ("fopen fin"); exit(1); } if ((fout = fopen("buylow.out", "w")) == NULL) { perror ("fopen fout"); exit(1); }
fscanf (fin, "%d", &nlen); for (lv = 0; lv < nlen; lv++) fscanf (fin, "%d", &num[lv]); /* 用DP计算最大长?/ for (lv = 0; lv < nlen; lv++) { max = 1; for (lv2 = lv-1; lv2 >= 0; lv2--) if (num[lv2] > num[lv] && len[lv2]+1 > max) max = len[lv2]+1; len[lv] = max; } for (lv = 0; lv < nlen; lv++) { if (len[lv] == 1) init_big(&cnt[lv], 1); else { init_big(&cnt[lv], 0); l = -1; max = len[lv]-1; for (lv2 = lv-1; lv2 >= 0; lv2--) if (len[lv2] == max && num[lv2] > num[lv] && num[lv2] != l) add(cnt[lv], cnt[lv2]); l = num[lv2]; } } } /* 找最长串*/ max = 0; for (lv = 0; lv < nlen; lv++) if (len[lv] > max) max = len[lv]; init_big(&ans, 0); l = -1; for (lv = nlen-1; lv >= 0; lv--) if (len[lv] == max && num[lv] != l) { add(ans, cnt[lv]); l = num[lv]; } /* output answer */ fprintf (fout, "%i ", max); out_num(fout, ans); fprintf (fout, "\n"); return 0; }