动态规划练习题(含答案)

  • 格式:docx
  • 大小:24.37 KB
  • 文档页数:10

动态规划练习题

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: subset

INPUT FORMAT

输入文件只有一行,且只有一个整数N

SAMPLE INPUT (file subset.in)

7

OUTPUT FORMAT

输出划分方案总数,如果不存在则输出0。

SAMPLE OUTPUT (file subset.out)

4

参考程序如下:

#include

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: prefix

INPUT FORMAT

输入数据的开头包括 1..200 个元素(长度为 1..10 )组成的集合,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 “.” 的行。集合中的元素没有重复。接着是大写字母序列 S ,长度为

1..200,000 ,用一行或者多行的字符串来表示,每行不超过 76 个字符。换行符并不是序列 S 的一部分。

SAMPLE INPUT (file prefix.in)

A AB BA CA BBC

.

ABABACABAABC

OUTPUT FORMAT

只有一行,输出一个整数,表示 S 能够分解成 P 中元素的最长前缀的长度。

SAMPLE OUTPUT (file prefix.out)

11

示例程序如下:

#include

#define MAXP 200

#define MAXL 10

char 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: inflate

INPUT FORMAT

第 1 行: M, N--竞赛的时间和题目"种类"的数目。

第 2-N+1 行: 两个整数:每个"种类"题目的分数和耗时。

SAMPLE INPUT (file inflate.in)

300 4

100 60

250 120

120 100

35 20

OUTPUT FORMAT

单独的一行包括那个在给定的限制里可能得到的最大的分数。

SAMPLE OUTPUT (file inflate.out)

605

{从第2个"种类"中选两题,第4个"种类"中选三题}

示例程序如下: #include

ifstream fin("inflate.in");

ofstream fout("inflate.out");

const short maxm = 10010;

long best[maxm], m, n;

void

main()

{

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: game1

INPUT FORMAT

第一行: 正整数N, 表示序列中正整数的个数。

第二行至末尾: 用空格分隔的N个正整数(大小为1-200)。

SAMPLE INPUT (file game1.in)

6

4 7 2 9

5 2

OUTPUT FORMAT

只有一行,用空格分隔的两个整数: 依次为玩家一和玩家二最终的得分。

SAMPLE OUTPUT (file game1.out)

18 11

参考程序如下:

#include

#define NMAX 101