dp联手题总结.docx
- 文档编号:7576810
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:27
- 大小:109.66KB
dp联手题总结.docx
《dp联手题总结.docx》由会员分享,可在线阅读,更多相关《dp联手题总结.docx(27页珍藏版)》请在冰豆网上搜索。
dp联手题总结
总结
做的……
不是令人满意的结果,历时一个月,靠,大梁半个月……
关键子工程(project.c/cpp/pas)
在大型工程的施工前,我们把整个工程划分为若干个子工程,并把这些子工程编号为1、2、……、N;这样划分之后,子工程之间就会有一些依赖关系,即一些子工程必须在某些子工程完成之后才能施工。
由于子工程之间有相互依赖关系,因此有两个任务需要我们去完成:
首先,我们需要计算整个工程最少的完成时间;同时,由于一些不可预测的客观因素会使某些子工程延期,因此我们必须知道哪些子工程的延期会影响整个工程的延期,我们把有这种特征的子工程称为关键子工程,因此第二个任务就是找出所有的关键子工程,以便集中精力管理好这些子工程,尽量避免这些子工程延期,达到用最快的速度完成整个工程。
为了便于编程,现在我们假设:
(1)根据预算,每一个子工程都有一个完成时间。
(2)子工程之间的依赖关系是:
部分子工程必须在一些子工程完成之后才开工。
(3)只要满足子工程间的依赖关系,在任何时刻可以有任何多个子工程同时在施工,也既同时施工的子工程个数不受限制。
(4)整个工程的完成是指:
所有子工程的完成。
例如,有五个子工程的工程规划表
五个子工程的工程规划表:
序号
完成时间
子工程1
子工程2
子工程3
子工程4
子工程5
子工程1
5
0
0
0
子工程2
4
0
0
0
子工程3
12
0
0
0
子工程4
7
1
1
0
0
子工程5
2
1
1
1
其中,表格中第I+1行J+2列的值如为0表示“子工程I”可以在“子工程J”没完成前施工,为1表示“子工程I”必须在“子工程J”完成后才能施工。
上述工程最快完成时间为14天,其中子工程1、3、4、5为关键子工程。
输入数据:
第1行为N,N是子工程的总个数,N≤200。
第2行为N个正整数,分别代表子工程1、2、……、N的完成时间。
第3行到N+2行,每行有N-1个0或1。
其中的第I+2行的这些0,1,分别表示“子工程I”与子工程1、2、…、I-1、I+1、…N的依赖关系,(I=1、2、……、N)。
每行数据之间均用一个空格分开。
输出数据:
如子工程划分不合理,则输出-1;
如子工程划分合理,则用两行输出:
第1行为整个工程最少的完成时间。
第2行为按由小到大顺序输出所有关键子工程的编号。
样例:
输入文件名:
project.in
5
541272
0000
0000
0000
1100
1111
输出文件名:
project.out
14
1345
关键路径。
2.求关键路径的最大的代价:
1)将网拓扑排序
2)以拓扑序列划分阶段
3)用动态规划求解关键路径
3.求关键路径的节点:
若结点的排列已经过拓扑排序,即序号前面的结点会影响序号后面结点的活动,如下图。
可使用如下算法:
(1)求活动最早可以开始的时间
eet[1]:
=0;eet[k]:
=max(eet[j]+r[j,k])
(2)求活动最迟应该开始的时间
et[n]:
=eet[n];et[k]:
=min(et[j]-r[k,j]);
(3) 关键路径通过点J,具有如下的性质:
eet[j]=et[j]
机器分配(machine.c/cpp/pas)
某总公司拥有高效生产设备M台,准备分给下属的N个分公司。
各分公司若获得这些设备,可以为总公司提供一定的盈利。
问:
如何分配这M台设备才能使国家得到的盈利最大?
求出最大盈利值。
分配原则:
每个公司有权获得任意数目的设备,但总台数不得超过总设备数M。
其中M<=100,N<=100。
输入数据:
第一行为两个整数M,N。
接下来是一个N×M的矩阵,其中矩阵的第i行的第j列的数Aij表明第i个公司分配j台机器的盈利。
所有数据之间用一个空格分隔。
输出数据:
只有一个数据,为总公司分配这M台设备所获得的最大盈利。
样例
输入文件名:
machine.in
32
123
234
输出文件名:
machine.out
4
状态的分析:
f[I,J]表示前I个公司分得J个机器所得的最大的价值,
则F[I,J]:
=MAX(F[I-1,J-K]+A[I,K]),目标为F[M,N];
编辑距离(edit.c/cpp/pas)
字符串是数据结构和计算机语言里很重要的数据类型,在计算机语言中,对于字符串我们有很多的操作定义,因此我们可以对字符串进行很多复杂的运算和操作。
实际上,所有复杂的字符串操作都是由字符串的基本操作组成。
例如,把子串a替换为子串b,就是用查找、删除和插入这三个基本操作实现的。
因此,在复杂字符串操作的编程中,为了提高程序中字符操作的速度,我们就应该用最少的基本操作完成复杂操作。
在这里,假设字符串的基本操作仅为:
删除一个字符、插入一个字符和将一个字符修改成另一个字符这三种操作。
我们把进行了一次上述三种操作的任意一种操作称为进行了一步字符基本操作。
下面我们定义两个字符串的编辑距离:
对于两个字符串a和b,通过上述的基本操作,我们可以把a变成b或b变成a;那么,把字符串a变成字符串b需要的最少基本字符操作步数称为字符串a和字符串b的编辑距离。
例如,如a=“ABC”,b=“CBCD”,则a与b的编辑距离为2。
你的任务就是:
编一个最快的程序来计算任意两个字符串的编辑距离。
输入数据:
第1行为字符串a;第2行为字符串b。
注:
字符串的长度不大于1000,字符串中的字符全为大写字母。
输出数据:
编辑距离。
样例
输入文件名:
edit.in
ABC
CBCD
输出文件名:
edit.out
2
状态的分析:
F[I,j]为第一串的前I个与第二串前J个的最小距离,
当STR1[I]=STR2[J]时F[I,J]:
=F[I-1,J-1]
否则,如果修改,则F[I,J]:
=F[I-1,J-1]+1;
如果删除,则F[I,J]:
=F[I-1,J]+1;
如果添加,则F[I,J]:
=F[I,J-1]+1;
求出其中的最小值就可以了。
硬币找零(coin.c/cpp/pas)
在现实生活中,我们经常遇到硬币找零的问题,例如,在发工资时,财务人员就需要计算最少的找零硬币数,以便他们能从银行拿回最少的硬币数,并保证能用这些硬币发工资。
我们应该注意到,人民币的硬币系统是100,50,20,10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01元,采用这些硬币我们可以对任何一个工资数用贪心算法求出其最少硬币数。
但不幸的是:
我们可能没有这样一种好的硬币系统,因此用贪心算法不能求出最少的硬币数,甚至有些金钱总数还不能用这些硬币找零。
例如,如果硬币系统是40,30,25元,那么37元就不能用这些硬币找零;95元的最少找零硬币数是3。
又如,硬币系统是10,7,5,1元,那么12元用贪心法得到的硬币数为3,而最少硬币数是2。
你的任务就是:
对于任意的硬币系统和一个金钱数,请你编程求出最少的找零硬币数;如果不能用这些硬币找零,请给出一种找零方法,使剩下的钱最少。
输入数据:
第1行,为N和T,其中1≤N≤50为硬币系统中不同硬币数;1≤T≤100000为需要用硬币找零的总数。
第2行为N个数值不大于65535的正整数,它们是硬币系统中各硬币的面值。
输出数据:
如T能被硬币系统中的硬币找零,请输出最少的找零硬币数。
如T不能被硬币系统中的硬币找零,请输出剩下钱数最少的找零方案中的最少硬币数。
样例
输入文件名:
coin.in
412
10751
输出文件名:
coin.out
2
很好的完全背包,以重量为阶段,对从小到大排好序的每个物品进行枚举。
最后找出有方案的最小的被找零的钱。
拦截导弹(文件名:
missile.c/cpp/pas)
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。
但是这种导弹拦截系统有一个缺陷:
虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
某天,雷达捕捉到敌国的导弹来袭。
由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入数据:
第一行为一个整数N,表示飞来的导弹个数,N<=100000
第二行为N个整数,依次表示导弹飞来的高度,高度数据为不大于30000的正整数。
输出数据:
第一行,输出计算这套系统最多能拦截多少导弹
第二行,输出要拦截所有导弹最少要配备多少套这种导弹拦截系统。
样例
输入文件:
missile.in
8
38920715530029917015865
输出文件:
missile.out
62
首先,可以发现,第一个是最大不降子序列,然后……嗯……第二问是最大上升子序列。
问题的关键是,在使用N*LOG(N)的算法时,二分的实现总是让我蛋疼的。
在写二分的代码时,要判断是否覆盖当前点或是当前点的下一个点。
整数划分(文件名:
separate.c/cpp/pas)
如何把一个正整数N(N长度<20)划分为M(M>1)个部分,使这N个部分的乘积最大。
N、M从键盘输入,输出最大值及一种划分方式。
输入数据:
第一行一个正整数T(T<=10000),表示有T组数据。
接下来T行每行两个正整数N,M。
输出数据:
对于每组数据
第一行输出最大值。
第二行输出划分方案,将N按顺序分成M个数输出,两个数之间用空格格开。
样例
输入文件:
separate.in
1
1992
输出文件:
separate.out
171
199
状态的转移:
F[I,J]是在前I个数中插入了J个乘号(I>J),其中最后一个一定是在I后的;
SUM[I,J]是从I到J的数字
然后再枚举插入乘号的位置,则
F[I,J]:
=MAX(F[K,J-1]*SUM[K+1,J];
注意记录。
利用栈来进行输出。
快餐问题(文件名:
meal.c/cpp/pas)
Peter最近在R市开了一家快餐店,为了招揽顾客,该快餐店准备推出一种套餐,该套餐由A个汉堡,B个薯条和C个饮料组成。
价格便宜。
为了提高产量,Peter从著名的麦当劳公司引进了N条生产线。
所有的生产线都可以生产汉堡,薯条和饮料,由于每条生产线每天所能提供的生产时间是有限的、不同的,而汉堡,薯条和饮料的单位生产时间又不同。
这使得Peter很为难,不知道如何安排生产才能使一天中生产的套餐产量最大。
请你编一程序,计算一天中套餐的最大生产量。
为简单起见,假设汉堡、薯条和饮料的日产量不超过100个。
输入数据:
第一行为三个不超过100的正整数A、B、C中间以一个空格分开。
第二行为3个不超过100的正整数p1,p2,p3分别为汉堡,薯条和饮料的单位生产耗时。
中间以一个空格分开。
第三行为为一个整数N(0<=0<=10),表示有N条流水线
第四行为N个不超过10000的正整数,其中Ti表示第i条生产流水线每天提供的生产时间,中间以一个空格分开。
输出数据:
仅一行,即每天套餐的最大产量。
样例
输入文件:
meal.in
222
122
2
66
输出文件:
meal.out
1
状态转移:
F[I,J,K]表示在前I个流水线上生产J件汉堡和K件薯条后所可生产的最多的饮料。
F[I,R+J,E+K]:
=MAX(F[I-1,J,K]+(C[I]-(R*V[1]+E*[2])divV[3]);(R+E<=100,E+K<=100,F[I,R+J,E+K]<=100且R+I与E+K的消耗时间不超过当前生产线的最大时间C[I])
因为最多可以生产100件,所以可以在递推时有一个较好的剪枝——贪心。
知道了A,B,C后,我们可以求得最理想的最大的套餐数
MAX:
=MIN(100divA,100divB),100divC);
可以在更新后与理想值比较,是否可以直接输出理想值。
注意在更新时要记着饮料最多为100,大于时要强制赋值为100。
物品装箱问题(文件名:
box.c/cpp/pas)
设有n种物品,记作A1、A2、…、An,对应于每个Ai(1<=i<=n)都有一个重量Awi和价值Avi(重量和价值都为正整数)。
另外,对应于每个Ai,都有一件可代替它的“代用品”Bi,Bi的重量和价值分别为Bwi和Bvi。
本题的任务是:
选择这n件物品或其代用品的一个子集装进背包,使总重量不超过给定重量TOT,同时使总价值VAL最高。
装填的第I步,要么装入Ai,要么装入Bi,要么Ai和Bi都不装。
输入数据:
第一行:
nTOT,n<=100,TOT<=10000
第二行:
AW1Av1BW1Bv1
第三行:
AW2Av2BW2Bv2
……
第n+1行:
AWnAvnBWnBvn
输入数据:
只有一个数为最大的价值
样例
输入文件:
box.in
420
8201231
23920
13311112
891336
输出文件:
box.out
40
01背包,在对第二个物品这记性更新时要注意,先进行上一次的最优的比较,然后对当前值进行比较取优。
火车进站(文件名:
train.c/cpp/pas)
火车站内往往设有一些主干线分叉出去的铁路支路,供火车停靠,以便上下客或装载货物。
铁路支路有一定长度;火车也有一定的长度,且每列火车的长度相等。
假设某东西向的铁路上,有一小站。
该站只有一条铁路支路可供火车停靠,并且该铁路支路最多能容纳M辆火车。
为了火车行驶的通畅,该站只允许火车自东方进站,自西方出站,且先进站的火车必须先出站,否则,站内火车将发生堵塞。
该火车站工作任务繁忙。
每天都有N辆自东方驶向西方的火车要求在预定时刻进站,并在站内作一定时间的停靠。
为了满足每辆进站火车的要求,小站的调度工作是井井有条地开展。
在小站每天的工作开始前,小站工作人员须阅读所有火车的进站申请,并决定究竞接受哪些火车的申请。
而对于不能满足要求的火车,小站必须提前通知它们,请它们改变行车路线,以免影响正常的铁路运输工作。
由于火车进站、出站的用时可以忽略不计,小站允许几辆火车同时进站或出站,且小站工作人员可以任意安排这些火车进站的先后排列次序。
小站的工作原则是尽量地满足申请火车的要求。
请你编一个程序,帮助工作人员考察某天所有火车的进站申请,计算最多能满足多少火车的要求。
输入数据:
共N+1行。
第一行是两个正整数N和M。
(N<=100,M<=3);
以下N行每行是一辆火车的进站申请,第i+1行的两个整数分别表示第i列火车的进站的时间和火车出站的时间。
输出数据:
仅一行,是一个正整数B,表示火车站最多能接纳的火车数量。
样例
train.in
63
24
17
36
57
810
911
train.out
5
凸多边形的三角剖分(division.c/cpp/pas)
给定一具有N个顶点(从1到N编号)的凸多边形,每个顶点的权均已知。
问如何把这个凸多边形划分成N-2个互不相交的三角形,使得这些三角形顶点的权的乘积之和最小?
输入数据:
第一行顶点数N(N<50)。
第二行N个顶点(从1到N)的权值,权值为小于32768的整数。
输出数据:
第一行为各三角形顶点的权的乘积之和最小值。
样例
division.in
5
121122123245231
division.out
12214884
区间动规,对于一个已知的凸多边形I->J,我们可以在I到J中(不包括I和J)找一个点K,分为小的凸多边形(i->k)和(K->J)和三角形(I,J,k);则在枚举点中找出最小的方案。
F[I,,J]:
=MIN(F[I,K]+F[I,J]+C[I]*C[J]*C[k]);
注意,不必考虑I>J的情况,因为在已枚举的小图形中,这种情况是可以通过组合的情况来实现的。
至此问题解决。
加分二叉树(文件名:
tree.c/cpp/pas)
设一个n个节点的二叉树tree的中序遍历为(l,2,3,…,n),其中数字1,2,3,…,n为节点编号。
每个节点都有一个分数(均为正整数),记第j个节点的分数为di,tree及它的每个子树都有一个加分,任一棵子树subtree(也包含tree本身)的加分计算方法如下:
subtree的左子树的加分×subtree的右子树的加分+subtree的根的分数
若某个子树为主,规定其加分为1,叶子的加分就是叶节点本身的分数。
不考虑它的空
子树。
试求一棵符合中序遍历为(1,2,3,…,n)且加分最高的二叉树tree。
要求输出;
(1)tree的最高加分
(2)tree的前序遍历
输入数据
第1行:
一个整数n(n<30),为节点个数。
第2行:
n个用空格隔开的整数,为每个节点的分数(分数<100)。
输出数据
第1行:
一个整数,为最高加分(结果不会超过4,000,000,000)。
第2行:
n个用空格隔开的整数,为该树的前序遍历。
样例
tree.in
5
571210
tree.out
145
31245
区间动规,F[I,J]表示在节点I到节点J的最大值,因为已知其中序遍历,所以可以直接枚举I和J。
枚举K,F[I,J]:
=MAX(F[I,K-1]*F[K+1,J]+C[k])。
记得预处理为1。
在输出时要注意,很大一部分纠结在前序输出上。
最长前缀(文件名:
Prefix.pas/c/cpp)
一些生物体的复杂结构可以用其基元的序列表示,而一个基元用一个大写英文字符串表示。
生物学家的一个问题就是一个这样的长序列分解为基元(字符串)的序列。
对于给定的基元集合P,如果可以从中选出N个基元P1,P2,P3,...,Pn,将它们各自对应的字符串依次连接后得到一个字符串S,称S可以由基元集合P构成。
在从P中挑选基元时,一个基元可以使用多次,也可不用。
例如,序列ABABACABAAB可以由基元集合{A,AB,BA,CA,BBC}构成。
字符串的前K个字符为该字符串的前缀,其长度为K。
请写一个程序,对于输入的基元集合P和字符串T,求出一个可以由基元集合P构成的字符串T的前缀,要求该前缀的长度尽可能长,输出其长度。
输入数据:
第一行是基元集合P中的基元数目N(1<=N<=100),随后有2N行,每两行描述一个基元,第一行为该基元的长度L(1<=L<=20)。
随后一行是一个长度为L的大写英文字符串,表示该基元。
每个基元互不相同。
最后一行描述要处理的字符串T,T由大写字母组成,最后一行是一个字符'.',表示字符串结束。
T的长度最小为1,最大不超过500000。
输出数据:
只有一行,一个数字,表示可以由P构成的T的最长前缀的长度。
样例:
prefix.in
5
1
A
2
AB
3
BBC
2
CA
2
BA
ABABACABAABCB.
prefix.out
11
背包,不知道当初是怎么想的,加了哈希判重。
很好。
判断当前的可执行性,就可以了。
求最长公共子序列(lcs.pas/c/cpp)
字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。
令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列
例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。
对给定的两个字符序列,求出他们最长的公共子序列。
输入数据:
第1行为第1个字符序列,都是大写字母组成,以”.”结束。
长度小于5000。
第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。
输出数据:
输出上述两个最长公共自序列的长度。
样例:
lcs.in
ABCBDAB.
BACBBD.
lcs.out
4
状态转移:
F[I,J]表示在ST1的第I位与ST2的第J位的最长公共子序列。
如果ST1[I]=ST2[J]则F[I,J]:
=F[I-1,J-1]+1
否则F[I,J]:
=MAX(F[I-1,J]+F[I,J-1]);
目标:
F[LENGTH(ST1),LENGTH(ST2)];
卡车更新问题(文件名:
truck.pas/c/cpp)
某人购置了一辆新卡车,从事个体运输业务.给定以下各有关数据:
R[t],t=0,1,2,...,k,表示已使用过t年的卡车,再工作一年所得的运费,它随t的增加而减少,k(k≤20)年后卡车已无使用价值.
U[t]:
t=0,1,...,k,表示已使用过t年的卡车,再工作一年所需的维修费,它随t的增加而增加.
C[t],t=0,1,2,...,k,表示已使用过t年的旧卡车,卖掉旧车,买进新车,所需的净费用,它随t的增加而增加.以上各数据均为实型,单位为"万元".
设某卡车已使用过t年,
①如果继续使用,则第t+1年回收额为R[t]-U[t],
②如果卖掉旧车,买进新车,则第t+1年回收额为R[0]-U[0]-C[t].
该运输户从某年初购车日起,计划工作N(N<=20)年,N年后不论车的状态如何,不再工作.为使这N年的总回收额最大,应在哪些年更新旧车?
假定在这N年内,运输户每年只用一辆车,而且以上各种费用均不改变.
输入数据:
第1行:
N(运输户工作年限)
第2行:
k(卡车最大使用年限,k≤20)
第3行:
R[0]R[1]...R[k]
第4行:
U[0]U[1]...U[k]
第5行:
C[0]C[1]...C[k]
输出数据:
第1行:
W(N年总回收额)
第2--N+1行:
每行输出3个数据:
每行输出3个数据:
年序号(从1到N按升序输出);
否更新(当年如果更新,输出1,否则输出0);
当年回收额(N年回收总额应等于W).
样例
Truck.in
4
5
876542
0.512345
0235810
Truck.out
24.5
107.5
215.5
315.5
406.0
选课(文件名:
course.pas/c/cpp)
大学里实行学分。
每门课程都有一定的学分,学生只要选修了这门课并考核通过就能获得相应的学分。
学生最后的学分是他选修的各门课的学分的总和。
每个学生都要选择规定数量的课程。
其中有些课程可以直接选修,有
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- dp 联手 总结