动态规划练习题USACO 2.2 Subset Sums题目如下:对于从1到N的连续整集合合,能划分成两个子集合,且保证每个集合的数字和是相等的。
举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:and {1,2}这是唯一一种分发(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数字和是相等的:{1,6,7} and {2,3,4,5} {注1+6+7=2+3+4+5}{2,5,7} and {1,3,4,6}{3,4,7} and {1,2,5,6}{1,2,4,7} and {3,5,6}给出N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出0。
程序不能预存结果直接输出。
PROGRAM NAME: subsetINPUT FORMAT输入文件只有一行,且只有一个整数NSAMPLE INPUT (file subset.in)7OUTPUT FORMAT输出划分方案总数,如果不存在则输出0。
SAMPLE OUTPUT (file subset.out)4参考程序如下:#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题目如下:在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。
生物学家对于把长的序列分解成较短的(称之为元素的)序列很感兴趣。
如果一个集合P 中的元素可以通过串联(允许重复;串联,相当于Pascal 中的“+” 运算符)组成一个序列S ,那么我们认为序列S 可以分解为P 中的元素。
并不是所有的元素都必须出现。
举个例子,序列ABABACABAAB 可以分解为下面集合中的元素:{A, AB, BA, CA, BBC}序列S 的前面K 个字符称作S 中长度为K 的前缀。
设计一个程序,输入一个元素集合以及一个大写字母序列,计算这个序列最长的前缀的长度。
PROGRAM NAME: prefixINPUT FORMAT输入数据的开头包括1..200 个元素(长度为 1..10 )组成的集合,用连续的以空格分开的字符串表示。
字母全部是大写,数据可能不止一行。
元素集合结束的标志是一个只包含一个“.” 的行。
集合中的元素没有重复。
接着是大写字母序列S ,长度为1..200,000 ,用一行或者多行的字符串来表示,每行不超过76 个字符。
换行符并不是序列S 的一部分。
SAMPLE INPUT (file prefix.in)A AB BA CA BBC.ABABACABAABCOUTPUT FORMAT只有一行,输出一个整数,表示S 能够分解成P 中元素的最长前缀的长度。
SAMPLE OUTPUT (file prefix.out)11示例程序如下:#include <stdio.h>#define MAXP 200#define MAXL 10char prim[MAXP+1][MAXL+1];int nump;int start[200001];char data[200000];int ndata;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);}while (1){fscanf (fin, "%s", prim[nump]);if (prim[nump][0] != '.') nump++;else break;}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]){best = lv;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])start[lv + lv3] = 1;}}if (start[ndata]) best = ndata;fprintf (fout, "%i\n", best);return 0;}USACO 3.1 Score Inflation题目如下:我们试着设计我们的竞赛以便人们能尽可能的多得分,这需要你的帮助。
我们可以从几个种类中选取竞赛的题目,这里的一个"种类"是指一个竞赛题目的集合,解决集合中的题目需要相同多的时间并且能得到相同的分数。
你的任务是写一个程序来告诉USACO的职员,应该从每一个种类中选取多少题目,使得解决题目的总耗时在竞赛规定的时间里并且总分最大。
输入包括竞赛的时间,M(1 <= M <= 10,000)和N,"种类"的数目1 <= N <= 10,000。
后面的每一行将包括两个整数来描述一个"种类":第一个整数说明解决这种题目能得的分数(1 <= points <= 10000),第二整数说明解决这种题目所需的时间(1 <= minutes <= 10000)。
你的程序应该确定我们应该从每个"种类"中选多少道题目使得能在竞赛的时间中得到最大的分数。
来自任意的"种类"的题目数目可能任何非负数(0或更多)。
计算可能得到的最大分数。
PROGRAM NAME: inflateINPUT FORMAT第 1 行: M, N--竞赛的时间和题目"种类"的数目。
第2-N+1 行: 两个整数:每个"种类"题目的分数和耗时。
SAMPLE INPUT (file inflate.in)300 4100 60250 120120 10035 20OUTPUT FORMAT单独的一行包括那个在给定的限制里可能得到的最大的分数。
SAMPLE OUTPUT (file inflate.out)605{从第2个"种类"中选两题,第4个"种类"中选三题}示例程序如下:#include <fstream.h>ifstream fin("inflate.in");ofstream fout("inflate.out");const short maxm = 10010;long best[maxm], m, n;voidmain(){short i, j, len, pts;fin >> m >> n;for (j = 0; j <= m; j++)best[j] = 0;for (i = 0; i < n; i++) {fin >> pts >> len;for (j = len; j <= m; j++)if (best[j-len] + pts > best[j])best[j] = best[j-len] + pts;}fout << best[m] << endl; // 由于数组元素不减,末元素最大}USACO 3.3 A Game题目如下:有如下一个双人游戏:N(2 <= N <= 100)个正整数的序列放在一个游戏平台上,两人轮流从序列的两端取数,取数后该数字被去掉并累加到本玩家的得分中,当数取尽时,游戏结束。
以最终得分多者为胜。
编一个执行最优策略的程序,最优策略就是使自己能得到在当前情况下最大的可能的总分的策略。
你的程序要始终为第二位玩家执行最优策略。
PROGRAM NAME: game1INPUT FORMAT第一行: 正整数N, 表示序列中正整数的个数。
第二行至末尾: 用空格分隔的N个正整数(大小为1-200)。
SAMPLE INPUT (file game1.in)64 7 2 95 2OUTPUT FORMAT只有一行,用空格分隔的两个整数: 依次为玩家一和玩家二最终的得分。
SAMPLE OUTPUT (file game1.out)18 11参考程序如下:#include <stdio.h>#define NMAX 101int best[NMAX][2], t[NMAX];int n;voidreadx () {int i, aux;freopen ("game1.in", "r", stdin);scanf ("%d", &n);for (i = 1; i <= n; i++) {scanf ("%d", &aux);t = t[i - 1] + aux;}fclose (stdin);}inline intmin (int x, int y) {return x > y ? y : x;}voidsolve () {int i, l;for (l = 1; l <= n; l++)for (i = 1; i + l <= n + 1; i++)best[l%2] = t[i + l - 1] - t[i - 1] - min (best[i + 1][(l - 1) % 2],best[(l - 1) % 2]);}void writex () {freopen ("game1.out", "w", stdout);printf ("%d %d\n", best[1][n % 2], t[n] - best[1][n % 2]);fclose (stdout);}intmain () {readx ();solve ();writex ();return 0;}USACO 3.4 Raucous Rockers题目如下:你刚刚得到了流行的“破锣摇滚”乐队录制的尚未发表的N(1 <= N <= 20)首歌的版权。