acm动态规划总结

acm动态规划总结
acm动态规划总结

动态规划题目总结(一)

对于一个有数字组成的二叉树,求由叶子到根的一条路径,使数字和最大,如:

7

38

8 1 0

2 7 4 4

4 5 2 6 5

这个是经典的动态规划,也是最最基础、最最简单的动态规划,典型的多段图。思路就是建立一个数组,由下向上动态规划,保存页子节点到当前节点的最大值,Java核心代码如下:

for(int i=num-2;i>=0;i--){

for(int j=0;j<=i;j++){

//该句是整个动态规划的核心

number[i][j]=Math.max(number[i+1][j],number[i+1][j+1])+number[i][j];

}

}

Pku acm 1579 Function Run Fun 动态规划题目总结(二)

Consider a three-parameter recursive function w(a, b, c):

if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns: 1

if a > 20 or b > 20 or c > 20, then w(a, b, c) returns: w(20, 20, 20)

if a < b and b < c, then w(a, b, c) returns: w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c)

otherwise it returns: w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1)

这本身就是一个递归函数,要是按照函数本身写递归式,结果肯定是TLE,这里我开了一个三维数组,从w(0,0,0)开始递推,逐步产生到w(20,20,20)的值,复杂度O(n^3).

总结:这道题是很地道的DP,因为它的子问题实在是太多了,所以将问题的结果保存起来,刘汝佳《算法艺术和信息学竞赛》中115页讲到自底向上的递推,这个例子就非常典型。总体来说这个题目还是非常简单的,不过这个思想是地道的动态规划。

Pku acm 2081 Recaman's Sequence 动态规划题目总结(三)

一道很简单的动态规划,根据一个递推公式求一个序列,我选择顺序的求解,即自底向上的递推,一个int数组result根据前面的值依此求出序列的每一个结果,另外一个boolean数组flag[i]记录i是否已经出现在序列中,求result的时候用得着,这样就避免

了查找。核心的java代码为:

for(i=1;i<=500000;i++)

{

if(result[i-1]-i>0&&flag[result[i-1]-i]==false)

{

result[i] = result[i-1]-i;

flag[result[i-1]-i] = true;

}

else

{

result[i] = result[i-1]+i;

flag[result[i-1]+i] = true;

}

}

Pku acm 1953 World Cup Noise 动态规划题目总结(四)

给定一个小于45的整数n,求n位2进制数中不含相邻1的数的个数。看似简单的一

对于n=1来说,以1结尾、以0结尾个数都是1,总和是2,下面过度到2:对于所有以1结尾的数,后面都可以加上0,变为n=2时以0结尾的,而只有结尾为0的数才能加上1(因为不能有两个连续0),这样就可以在n=2的格里分别填上1、2,总和算出来为3,以此类推,我们可以算出所有n<=45的值,然后根据输入进行相应输出。核心代码如下:int i,num,count,array[50][2],j=0;

array[1][1] = 1;

array[1][0] = 1;

for(i=2;i<50;i++)

{

array[i][0] = array[i-1][1];

array[i][1] = array[i-1][1]+array[i-1][0];

}

我们可以继续找出规律,其实这个就是斐波那切数列数列:

F[N] = F[N-1]+F[N-2];可以继续简化代码。

Pku acm 1458 Common Subsequence 动态规划题目总结(五)

求两个string的最大公共字串,动态规划的经典问题。算法导论有详细的讲解。

下面以题目中的例子来说明算法:两个string分别为:abcfbc和abfca。创建一个二维数组result[][],维数分别是两个字符串长度加一。我们定义result[i][j]表示X i和Y j 的最长子串(LCS).当i或j等于0时,result[i][j]=0. LCS问题存在一下递归式:

result[i][j] = 0 i=0 or j=0

result[i][j] = result[i-1][j-1] X i= =Y j

result[i][j] = MAX(result[i-1][j], result[i][j-1]) X i! =Y j

对于以上例子,算法如下:

含有斜向上的箭头对应的字符是其中的一个lcs。

Java代码的核心部分如下:

for(int i=0;i

result[i][0] = 0;

}

for(int i=0;i

result[0][i] = 0;

}

for(int i=1;i<=length1;i++){

for(int j=1;j<=length2;j++){

if(str1.charAt(i-1)==str2.charAt(j-1))

result[i][j] = result[i-1][j-1]+1;

else

result[i][j] = result[i-1][j]>result[i][j-1]?result[i-1][j]:result[i][j-1];

}

}

System.out.println(result[length1][length2]);

Pku acm 1159 Palindrome 动态规划题目总结(七)

给一个字符串,求这个字符串最少增加几个字符能变成回文,如Ab3bd可以增加2个字符变为回文:Adb3bdA。通过这样的结论可以和最长公共子串联系起来(未证明):S和S' (注:S'是S的反串)的最长公共子串其实一定是回文的。这样我们就可以借助lcs来解决该题,即用s的长度减去lcs的值即可。核心的Java代码为:

total-LCS(string,new StringBuffer(string).reverse().toString());

//函数LCS返回两个string的lcs的长度

Pku acm 1080 Humman Gene Function 动态规划题目总结(八)

这是一道比较经典的DP,两串基因序列包含A、C、G、T,每两个字母间的匹配都会

产生一个相似值,求基因序列(字符串)匹配的最大值。

这题有点像求最长公共子序列。只不过把求最大长度改成了求最大的匹配值。用二维数组opt[i][j]记录字符串a中的前i个字符与字符串b中的前j个字符匹配所产生的最大值。假如已知AG和GT的最大匹配值,AGT和GT的最大匹配值,AG和GTT的最大匹配值,求AGT和GTT的最大匹配值,这个值是AG和GT的最大匹配值加上T 和T的匹配值,AGT和GT的最大匹配值加上T 和-的匹配值,AG和GTT的最大匹配值加上-和T的匹配值中的最大值,所以状态转移方程:

opt[i][j] =

第0行,第0列表示null和字符串匹配情况,结果是’-’和各个字符的累加:for(i=1;i<=num1;i++)

opt[0][i] = opt[0][i-1]+table('-',a[i-1]);

for(i=1;i<=num2;i++)

opt[i][0] = opt[i-1][0]+table('-',b[i-1]);

opt[num2][num1]即为所求结果。

Pku acm 2192 Zipper 动态规划题目总结(九)

这个题目要求判断2个字符串能否组成1个字符串,例如cat和tree能组成tcraete。我们定义一个布尔类型的二维数组 array,array[i][j]表示str1[i]和str2[j]能否组成str[i+j].i=0或者j=0表示空字符串,所以初始化时,array[0][j]表示str1的前j个字符是否和str都匹配。

对于str=tcraete:

可以证明:当array[i-1][j]( array[i][j]上面一格)和array[i][j-1]( array[i][j]左面一格)都为0时,array[i][j]为0.当array[i-1][j]( array[i][j]上面一格)为1且左面字母为str[i+j]时或者当array[i][j-1]( array[i][j]左面一格)为1且上面字母为str[i+j]时,array[i][j]为1.这就是状态转移方程为。

核心的Java代码:

if(array[i][j-1]&&str1.charAt(j-1)==str.charAt(i+j-1)||array[i-1][j]&&str2.

charAt(i-1)==str.charAt(i+j-1))

array[i][j] = true;

else

array[i][j] = false;

Pku acm 3356 AGTC 动态规划题目总结(十)

一个字符串可以插入、删除、改变到另一个字符串,求改变的最小步骤。和最长公共子序列类似,用二维数组opt[i][j]记录字符串a中的前i个字符到字符串b中的前j个字符匹配所需要的最小步数。假如已知AG到GT的最小步数,AGT到GT的最小步数,AG到GTT 的最小步数,求AGT到GTT的最小步数,此时T= =T,这个值是AG到GT的最小步数,AGT 到GT的最小步数加一(AGT到GT的最小步数等于AGTT到GTT的最小步数,加一是将T删除的一步),AG到GTT的最小步数加一(AG到GTT的最小步数等于AGT到GTTT的最小步数,加一是在AGT上增加T的一步)。假如已知AG到GT的最小步数,AGA到GT的最小步数,AG 到GTT的最小步数,求AGA到GTT的最小步数,此时A! =T,这个值是AG到GT的最小步数加一(A改变为T),AGA到GT的最小步数加一(AGA到GT的最小步数等于AGAT到GTT的最小步数,加一是将T删除的一步),AG到GTT的最小步数加一(AG到GTT的最小步数等于AGA 到GTTA的最小步数,加一是在GTTA上删除A的一步)。所以状态转移方程:

if(str1.charAt(i-1)==str2.charAt(j-1))

array[i][j] = Math.min(Math.min(array[i-1][j-1], array[i-1][j]+1), array[i][j-1]+1);

else

array[i][j] = Math.min(Math.min(array[i-1][j-1]+1, array[i-1][j]+1), array[i][j-1]+1);

初始化的时候和最长公共子序列不同,因为第0行,第0列表示null转化到字符串情况,结果是字符串的长度:

for(int i=0;i<=m;i++){

array[i][0] = i;

}

for(int i=0;i<=n;i++){

array[0][i] = i;

Pku acm 1887 Testing the CATCHER 动态规划题目总结(十一)

题目叙述很繁琐,其实就是求最长下降子序列,这一类题也是动态规划的典型题。这类问题有两种算法,一种 T(o) = O(n^2),另一种T(o) = O(nlogn),这里用第一种,在1631 Bridging signals的解题报告中介绍第二种。

创建一个一维数组num_array[j],max_array[],num_array[j]表示序列的元素,max_array[i]表示以第i个元素结尾的序列中的最长下降子序列,初始化为1,对于一个max_array[i],遍历前面的每个元素j,如果num_array[j]> num_array[i]且max_array[j]>= max_array[i],那么max_array[j]就要加1,所以递推公式为:

if(num_array[i]<=num_array[j]&&max_array[i]<=max_array[j])

max_array[i]++;

最后选最大的一个max_array[i]就是最长下降子序列的个数。Java关键部分的代码:

for(int i=1;i

for(int j=0;j

if(num_array[i]<=num_array[j]&&max_array[i]<=max_array[j])

max_array[i]++;

}

max_value = (max_array[i]>max_value)?max_array[i]:max_value;

}

max_value是最后的结果。

Pku acm 2533 Longest Ordered Subsequence 动态规划题目总结(十二)

这个题目和1887 Testing the CATCHER一模一样,没有什么值得说的,关键的c代码如下:for(i=1;i<=n;i++)

{

for(j=1;j

if(max[i]<=max[j]&&num[i]>num[j])

max[i]++;

if(max[i]>result)

result=max[i];

}

printf("%d\n",result);

Pku acm 1631 Bridging signals 动态规划题目总结(十三)

这个题目可以转化为最长上升子序列,这样这个题目似乎就和2533 Longest Ordered Subsequence 1887 Testing the CATCHER一样了,迅速写下代码,结果超时!看来只能用O(nlogn)的算法了。

在O(n^2)的算法中:创建一个一维数组array[j],opt[],array[j]表示序列的元素,opt[i]表示以第i个元素结尾的序列中的最长下降子序列,初始化为1,对于一个opt[i],遍历前面的每个元素j,如果array[j]>array[i]且opt[j]>=opt[i],那么opt[j]就要加1,在这里,遍历前面的每个元素j,寻找此前最大的子序列时间复杂度为O(n),如果我们在一个有序的序列中查找此前最大的序列长度,我们就可以用二分查找,时间复杂度就会降为O(logn),总的时间复杂度就会为O(nlogn)。为此,我们增加一个一维数组B,B[i]表示当前

i=1时,opt[i]=1 B[i]=4(当前为1的序列的末尾元素的最小值)

i=3时,6大于2,所以opt[i]=1+1,将B[2]更新为6

i=4时,3在2 6之间,所以opt[i]=1+1,将B[2]更新为3

i=6时,5大于3,所以opt[i]=2+1,将B[3]更新为5

前序列为i的末尾元素的最小值。以上“2不大于4”,“3在2 6之间”等等的判断采用二分查找,所以总的时间复杂度为:O(nlogn),核心的c代码如下:

for(i=1;i<=n;i++)

{

num = array[i];

left = 1;

right = Blen;

while(left<=right)

{

mid = (left+right)/2;

if(B[mid]

left = mid+1;

else

right = mid-1;

}

opt[i] = left;

B[left] = num;

if(Blen

Blen = left;

if(max

max = opt[i];

}

printf("%d\n",max);

Pku acm 1157 LITTLE SHOP OF FLOWERS 动态规划题目总结(十四)

该题也是经典的动态规划,题目叙述的依然很麻烦,其实简化一下就是这样的:例如下面这个例子就是:3表示行,5表示列,然后在下面的3行5列每一行选一个数,使这3个数最大,要求选的数列数必须依次增大,就是从左上方想右下方选3个数使和最大。

3 5

7 23 -5 -24 16

5 21 -4 10 23

-21 5 -4 -20 20

我们用opt定义以当前I j为结尾的花的排序的最大值,用r*(-50)表示负无穷,初始

从第二行开始,对于第i行第j列,对于i>=j,遍历i-1行前j列,求出当前最大值。

最后取第i行最大值即可,核心的c代码:

for(i=2;i<=r;i++)

for(j=1;j<=c;j++)

if(j>=i)

for(k=1;k

if(opt[i][j]

opt[i][j]=opt[i-1][k]+origin[i][j];

Pku acm 1088 滑雪动态规划题目总结(十五)

1 2 3 4 5

16 17 18 19 6

15 24 25 20 7

14 23 22 21 8

13 12 11 10 9

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。输出最长区域的长度。

Opt[i][j]表示位置i j上最大的下降距离,如果其周围4个点存在高度比i j高,且opt没有ij 大的点,则opt[i][j]=opt[周围]+1;另外,这个问题中存在大量重复问题,应该将计算的结果存储起来,避免重复的计算。

关键部分的c代码为:

for(k=0;k<4;k++)

{

if(isIn(i+dx[k],j+dy[k]) && heigth[i][j]

{

int num = dp(i+dx[k],j+dy[k]);

if(opt[i][j]<=num)

{

opt[i][j] = num+1;

}

}

}

其中const int dx[] = {0,0,-1,1},dy[] = {-1,1,0,0};表示一个点周围的4个点。

Pku acm 1050 To the Max 动态规划题目总结(十六)

题目的意思很简单,在一个矩阵里面找它的子矩阵,使得子矩阵数值之和到达最大。其实就是最大子段和问题在二维空间上的推广。先说一下一维的情况吧:设有数组a0,a1…an,找除其中连续的子段,使它们的和达到最大。假如对于子段:9 2 -16 2 temp[i]表示以ai结尾的子段中的最大子段和。在已知temp[i]的情况下,求temp [i+1]的方法是:

如果temp[i]>0 temp [i+1]= temp[i]+ai(继续在前一个子段上加上ai),否则temp[i+1]=ai(不加上前面的子段),也就是说状态转移方程:

temp[i] = (temp[i-1]>0?temp[i-1]:0)+buf[i];

对于刚才的例子 temp: 9 11 -5 2,然后取temp[]中最大的就是一维序列的最大子段。求一维最大子段和的函数:

int getMax(int buf[100],int n)

{

int temp[101],max=n*(-127);

memset(temp,0,4*(n+1));

for(int i=1;i<=n;i++)

{

temp[i] = (temp[i-1]>0?temp[i-1]:0)+buf[i];

if(max

max=temp[i];

}

return max;

}

下面扩展到二维的情况:考察下面题目中的例子:

0-2 -7 0

9 2 -6 2

-4 1 -4 7

-1 8 0 -2

我们分别用i j表示起始行和终止行,遍历所有的可能:

for(i=1;i<=n;i++)

for(j=i;j<=n;j++) {}

我们考察其中一种情况 i=2 j=4,这样就相当与选中了2 3 4三行,求那几列的组合能获得最大值,由于总是 2 3 4行,所以我们可以将这3行”捆绑”起来,变为求4(9-4-1),11(8+2+1),-10(-6-4+0),7(7+2-2)的最大子段和,ok,问题成功转化为一维的情况!

Pku acm 1014 Dividing 动态规划题目总结(十七)

刚AC了,趁热打铁,写下解题报告,这道题很早就在joj上做过,当时不知道dp,只会用很菜的方法,结果即使joj这道题仅要求10s还是会超时!

思想:本题是找按价值均分大理石的方案是否存在,由于分配时不能破坏大理石,所以有个显而易见的剪枝:当所有的大理石的总价值为奇数时肯定不能被均分。把问题转化一下即:由一个人能否从原大理石堆中取出总价值为原来一半的大理石,本题的主要算法是动态规划,数组flag代表状态,设总价值为sum.当flag[k]==true时,说明,可以有一人获得价值k,另外一人获得价值V-k的大理石分配方案。反之若flag[k]=false说明这种分配方案不存在.我们的任务就是计算出flag[sum/2]是true还是false,显然有flag[0]==true的方案存在,即一个人什么都不分,另外一个人拿走全部的大理石.

设i(1<<6)为石头的价值,试想若flag[k]==true,如果能再向k中增加一价值为i的大理石,则flag[k+i]==true必然成立.石头有两个属性,一个是价值另一个是数量,这里array[i]代表价值为i的大理石的数量,我们根据其中一个属性:价值来划分阶段。即for (int i=1;i<=6;i++),flag[k]表示状态是否存在(这里的状态是指能否从原石头堆中分出价值为k的新石头堆)。在初始阶段是i=1,初始状态是flag[0]=true,max代表目前满足flag[k]==true这一条件的k的最大值。

for(int j=max;j>=0;j--)

//从当前最大值flag开始,根据前面提到的flag[j]==true成立则flag[j+i]==true亦成立的理论,在原有状态flag[j]==true已存在的条件下加入stone[i]阶段的石头,得到新的状态

还是举个例子吧:3 0 1 2 0 0

对于i=2 array[2] = 0 不考察

对于i=3 array[3] = 1 因为flag[0] flag[1], flag[2], flag[3]= true,所以flag[3],

这样程序的基本框架就有了:dp函数如下:

bool dp(int array[7])

{

bool flag[60001];

int i,j,k,sum = 0,max=0;

for(i=1;i<=6;i++)

sum += array[i]*i;

if(sum%2!=0)

return false;

memset(flag,0,sizeof(flag));

flag[0] = true;

for(i=1;i<=6;i++)

{

if(array[i]>0)

{

for(j=max;j>=0;j--) //至于为什么要从大到小,写成从小到大的,调试一下就可以看出问题,//比如有1个1,原来flag[0] = true,循环一遍后flag[1] = true,此时再判断flag[1]=true,继续flag[2] = true就不//合题意了,从大到小可以解决这个问题

{

if(flag[j])

{

for(k=1;k<=array[i];k++)

{

if(j+k*i==sum/2)

return true;

else if(j+k*i

{

if(j+k*i>max) max = j+k*i;

if(j+k*i>sum/2) max = sum/2;

flag[j+k*i] = true;

}

}

}

}

}

}

return false;

}

这样问题就解决了,submit,结果超时,从joj上试了一下,结果ac,6s多,距离poj 的1s还很远。我们考察如果flag[j+k*i]已经等于true,就不用继续循环下一个k了,直接break就可以了,具体原因是这样的:

假设现在flag[]的序列是这样的:1 1 0 1 1 0 1 1 0 1,当前考察的是 i=3;array[i]=5,就是要在这个基础上加上5个3,按照程序的意思,从最后一个1开始依此加上3,将其值变为1,一共加上5个,然后在倒数第二个1上依此加上3,将其值变为1,一共加上5个,这个过程不会遇见flag=1的情况,给倒数第三个1依此加3的时候,会遇到:flag=1,这个时候就可以break了,因为这时候还需要加的4个3都在最后一个1加5个3时候加过了,这里要注意的是,给每个1加上3时候,只会遇到”旧的”flag=1,不会遇到新增加的flag=1,而旧的1已经加过了array[i]个i,所以就不用加了,直接退出就行了。

修改后的代码:

for(i=1;i<=6;i++)

{

if(array[i]>0)

{

for(j=max;j>=0;j--)

{

if(flag[j])

{

for(k=1;k<=array[i];k++)

{

if(j+k*i==sum/2)

return true;

if(j+k*i>sum/2||flag[j+k*i])

break;

flag[j+k*i] = true;

}

}

}

}

max += array[i]*i;

if(max>sum/2) max = sum/2;

}

Pku acm 1160 post office 动态规划题目总结(十八)

题目给出m个村庄及其距离,给出n个邮局,要求怎么建n个邮局使代价最小。

思路:用opt[i][j]记录把前i个邮局建到前j个村庄中的最优解,用cost[i][j]记录所有在i到j村庄中,建1个邮局的最小代价。显然邮局应该设到中点。让前i个邮局覆盖前j个村庄,第i+1个邮局覆盖第j+1至j+k个村庄(j+k<=n),则状态转移方程为

opt[i+1][j+k]=min{opt[i][j]+cost[j+1][j+k];} (k+j<=n)

Cost数组存放从i到j中有一个邮局的最小代价,显然该邮局应该放在中间,构造cost 的代码和结果如下:

for(i=1;i<=m;i++)

for(j=i;j<=m;j++)

{

cost[i][j] = 0;

mid = (i+j)/2;

for(k=i;k<=j;k++)

cost[i][j]+=(distance[mid]-distance[k])>=0 ?

distance[mid]-distance[k]:distance[k]-distance[mid];

Opt[i][j] 表示前i个邮局覆盖前j个村庄的最小代价,对于i=1来说,opt[i][j] = cost[i][j],让前2个邮局覆盖前j个村庄,也就是i=2的情况,可能是一下情况的最优解:第一个邮局覆盖第一个村庄,第二个村庄覆盖2-j个村庄,或者第一个邮局覆盖第1-2个村庄,第二个村庄覆盖3-j个村庄,第一个邮局覆盖第1-3个村庄,第二个村庄覆盖4-j个村庄,等等等等。该部分的代码如下:

for(i=0;i<=n;i++)

for(j=0;j<=m;j++)

if(opt[i][j]<3000000)

{

for(k=1;j+k<=m;k++)

{

if(opt[i+1][j+k]>opt[i][j]+cost[j+1][j+k])

{

opt[i+1][j+k] = opt[i][j]+cost[j+1][j+k];

}

}

}

Pku acm 1125 Stockbroker Grapevine 动态规划题目总结(十九) 有向图中每一对顶点间的最短路径问题,典型的弗洛伊德算法。 问题描述:已知一个含有n 个顶点的各边权值均大于0的带权有向图,对每对顶点vi !=vj ,要求求出每一对顶点之间的最短路径和最短路径长度。 解决方案:弗洛伊德(floyd)算法

对于这样一个例子:

A0[i][j]=cost[i][j]:

核心的c 代码如下:

for(int k=1;k<=n;k++) //生成A0,A1,A2...的循环 for(int i=1;i<=n;i++) //行 for(int j=1;j<=n;j++) //列 //如果是i==k||j==k||i==j 就保持不变,否则取最小值 array[i][j]=(i==k||j==k||i==j)?array[i][j]:

((array[i][j]<(array[i][k]+array[k][j])?array[i][j]:(array[i][k]+array[k][j])))

;

最后根据题意,取每行最大值中的最小值即可。

Pku acm 1179 Polygon 动态规划题目总结(二十)

多边形游戏是一个单人玩的游戏,开始时有一个由n个顶点构成的多边形。每个顶点被赋予一个整数值,每条边被赋予一个运算符“+”或“*”。所有边依次用整数从1到n编号。游戏第1步,将一条边删除。

随后n-1步按以下方式操作:

(1)选择一条边E以及由E连接着的2个顶点V1和V2;

(2)用一个新的顶点取代边E以及由E连接着的2个顶点V1和V2。将由顶点V1和V2的整数值通过边E上的运算得到的结果赋予新顶点。

最后,所有边都被删除,游戏结束。游戏的得分就是所剩顶点上的整数值。

问题:对于给定的多边形,计算最高得分。分析:

?在所给多边形中,从顶点i(1≤i≤n)开始,长度为j(链中有j个顶点)的顺时针链p(i,j) 可表示为v[i],op[i+1],…,v[i+j-1]。

?如果这条链的最后一次合并运算在op[i+s]处发生(1≤s≤j-1),则可在op[i+s]处将链分割为2个子链p(i,s)和p(i+s,j-s)。

?设m1是对子链p(i,s)的任意一种合并方式得到的值,而a和b分别是在所有可能的合并中得到的最小值和最大值。m2是p(i+s,j-s)的任意一种合并方式得到的值,而c和d分别是在所有可能的合并中得到的最小值和最大值。依此定义有a≤m1≤b,c≤m2≤d

(1)当op[i+s]='+'时,显然有a+c≤m≤b+d

(2)当op[i+s]='*'时,有min{ac,ad,bc,bd}≤m≤max{ac,ad,bc,bd}

?换句话说,主链的最大值和最小值可由子链的最大值和最小值得到。

这道题收获非常多:

1.已经定义了变量max,然后调用一个已经定义的函数max时报错:term does not evaluate to a function,原因是之前定义了一个int max;所以max(a,b)是把变量错误的当作函数使用

2.由于是一个环,所以下标要对n取模,这里还有一个技巧,例如当n=4时,4对4取模为0,不合要求,所以应该减一取模后加一

3.该例输入为:

4

t -7 t 4 x 2 x 5

开始输入语句为:

scanf("%d",&n);

for(i=1;i<=n;i++)

{

scanf("%c",&edge[i]);

scanf("%d",&vertex[i]);

}

读入了很多空格,因为空格也是char,然后修改为:

scanf("%d",&n);

for(i=1;i<=n;i++)

{

scanf("%c",&edge[i]);

scanf("%d",&vertex[i]);

if(i!=n)

scanf("%c",&edge[0]);

}

就是如果不是最后一个数字,读取数字后读取一个空格,然而这个时候还是无法正常读入,因为4后面有一个换行,被错误的读入到edge[1]中,所以在读取4是加一个\n scanf("%d\n",&n);

for(i=1;i<=n;i++)

{

scanf("%c",&edge[i]);

scanf("%d",&vertex[i]);

if(i!=n)

scanf("%c",&edge[0]);

}

最后改为了:

scanf("%d\n",&n);

for(i=1;i<=n;i++)

{

scanf(" %c",&edge[i]);

scanf("%d",&vertex[i]);

}

4.提交后 Time Limit Exceeded

发现代码中竟然有:

this_max = Max(getMaxResult(vertexth,i-1,true)*getMaxResult((vertexth+i-1)%n+1,length-i,tr ue),

getMaxResult(vertexth,i-1,true)*getMaxResult((vertexth+i-1)%n+1,length -i,false),

getMaxResult(vertexth,i-1,false)*getMaxResult((vertexth+i-1)%n+1,length-i,true) ,

getMaxResult(vertexth,i-1,false)*getMaxResult((vertexth+i-1)%n+1,length-i,false ));

这种语句,不Time Limit Exceeded 就奇怪了,接着改为:用变量保存结果,然后取最大值:

int firstTrue = getMaxResult(vertexth,i-1,true);

int secondTrue = getMaxResult((vertexth+i-1)%n+1,length-i,true);

int firstFalse = getMaxResult(vertexth,i-1,false);

int secondFalse = getMaxResult((vertexth+i-1)%n+1,length-i,false);

this_max = Max(firstTrue*secondTrue,firstTrue*secondFalse,firstFalse*secondTrue,firstFalse *secondFalse);

5.结果还是 Time Limit Exceeded 然后想到可能多次求一个

getMaxResult,比如可能多次求一个getMaxResult(3,4,true),所以应该将结果保存起来,这正是动态规划的本质!刘汝佳《算法艺术和信息学竞赛》中115页讲到技艺化搜索,这个例子就非常典型。定义一个3维数组,然后初始化为一个很小的值,然后调用getMaxResult 时先判断是不是已经计算过了(就是数组中是不是已经有值了),如果计算过就直接返回,否则在返回之前将值保存到数组中!

ACM经典算法及配套练习题

POJ上的一些水题(可用来练手和增加自信) (poj3299,poj2159,poj2739,poj1083,poj2262,poj1503,poj3006,p oj2255,poj3094) 初期: 一.基本算法: (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586) (3)递归和分治法. (4)递推. (5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法: (1)图的深度优先遍历和广度优先遍历. (2)最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra) (poj1860,poj3259,poj1062,poj2253,poj1125,poj2240) (3)最小生成树算法(prim,kruskal) (poj1789,poj2485,poj1258,poj3026) (4)拓扑排序(poj1094) (5)二分图的最大匹配(匈牙利算法) (poj3041,poj3020) (6)最大流的增广路算法(KM算法). (poj1459,poj3436) 三.数据结构. (1)串(poj1035,poj3080,poj1936) (2)排序(快排、归并排(与逆序数有关)、堆排) (poj2388,poj2299) (3)简单并查集的应用. (4)哈希表和二分查找等高效查找法(数的Hash,串的Hash) (poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503) (5)哈夫曼树(poj3253) (6)堆 (7)trie树(静态建树、动态建树) (poj2513) 四.简单搜索 (1)深度优先搜索(poj2488,poj3083,poj3009,poj1321,poj2251) (2)广度优先搜索(poj3278,poj1426,poj3126,poj3087.poj3414) (3)简单搜索技巧和剪枝(poj2531,poj1416,poj2676,1129) 五.动态规划 (1)背包问题. (poj1837,poj1276) (2)型如下表的简单DP(可参考lrj的书page149): 1.E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533) 2.E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij} (最长公共子序列) (poj3176,poj1080,poj1159) 3.C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.(最优二分检索树问题) 六.数学 (1)组合数学:

acm动态规划总结

动态规划题目总结(一) 对于一个有数字组成的二叉树,求由叶子到根的一条路径,使数字和最大,如: 7 38 8 1 0 2 7 4 4 4 5 2 6 5 这个是经典的动态规划,也是最最基础、最最简单的动态规划,典型的多段图。思路就是建立一个数组,由下向上动态规划,保存页子节点到当前节点的最大值,Java核心代码如下: for(int i=num-2;i>=0;i--){ for(int j=0;j<=i;j++){ //该句是整个动态规划的核心 number[i][j]=Math.max(number[i+1][j],number[i+1][j+1])+number[i][j]; } } Pku acm 1579 Function Run Fun 动态规划题目总结(二) Consider a three-parameter recursive function w(a, b, c): if a <= 0 or b <= 0 or c <= 0, then w(a, b, c) returns: 1 if a > 20 or b > 20 or c > 20, then w(a, b, c) returns: w(20, 20, 20) if a < b and b < c, then w(a, b, c) returns: w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c) otherwise it returns: w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1) 这本身就是一个递归函数,要是按照函数本身写递归式,结果肯定是TLE,这里我开了一个三维数组,从w(0,0,0)开始递推,逐步产生到w(20,20,20)的值,复杂度O(n^3). 总结:这道题是很地道的DP,因为它的子问题实在是太多了,所以将问题的结果保存起来,刘汝佳《算法艺术和信息学竞赛》中115页讲到自底向上的递推,这个例子就非常典型。总体来说这个题目还是非常简单的,不过这个思想是地道的动态规划。 Pku acm 2081 Recaman's Sequence 动态规划题目总结(三) 一道很简单的动态规划,根据一个递推公式求一个序列,我选择顺序的求解,即自底向上的递推,一个int数组result根据前面的值依此求出序列的每一个结果,另外一个boolean数组flag[i]记录i是否已经出现在序列中,求result的时候用得着,这样就避免

ACM训练计划

ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短路(Floyd、Dijstra,BellmanFord) 2.最小生成树(先写个prim,kruscal要用并查集,不好写) 3.大数(高精度)加减乘除 4.二分查找. (代码可在五行以内) 5.叉乘、判线段相交、然后写个凸包. 6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简) 7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式. 8. 调用系统的qsort, 技巧很多,慢慢掌握. 9. 任意进制间的转换 第二阶段:练习复杂一点,但也较常用的算法。 如: 1. 二分图匹配(匈牙利),最小路径覆盖 2. 网络流,最小费用流。 3. 线段树. 4. 并查集。 5. 熟悉动态规划的各个典型:LCS、最长递增子串、三角剖分、记忆化dp 6.博弈类算法。博弈树,二进制法等。 7.最大团,最大独立集。 8.判断点在多边形内。 9. 差分约束系统. 10. 双向广度搜索、A*算法,最小耗散优先. 相关的知识 图论 路径问题 0/1边权最短路径 BFS 非负边权最短路径(Dijkstra) 可以用Dijkstra解决问题的特征 负边权最短路径 Bellman-Ford Bellman-Ford的Yen-氏优化 差分约束系统 Floyd 广义路径问题 传递闭包 极小极大距离/ 极大极小距离

Euler Path / Tour 圈套圈算法 混合图的Euler Path / Tour Hamilton Path / Tour 特殊图的Hamilton Path / Tour 构造 生成树问题 最小生成树 第k小生成树 最优比率生成树 0/1分数规划 度限制生成树 连通性问题 强大的DFS算法 无向图连通性 割点 割边 二连通分支 有向图连通性 强连通分支 2-SAT 最小点基 有向无环图 拓扑排序 有向无环图与动态规划的关系 二分图匹配问题 一般图问题与二分图问题的转换思路 最大匹配 有向图的最小路径覆盖 0 / 1矩阵的最小覆盖 完备匹配 最优匹配 稳定婚姻 网络流问题 网络流模型的简单特征和与线性规划的关系最大流最小割定理 最大流问题 有上下界的最大流问题 循环流 最小费用最大流/ 最大费用最大流

Acm集训营培训心得

Acm集训营培训心得 参加暑期acm训练营的培训,让我收获了好多,感想也特别特别多,也学会了许多。所以特别感谢集训营中为我们上课的老师对我们做的培训。 经过特训营的培训,我了解到了许多关于acm的一系列知识。我感触特别深。作为ACM的新手,有兴趣而经验不足,然而有些热心的学者与老师多是向新手推荐书籍,如刘汝佳的算法竞赛入门经典,算法艺术与信息学竞赛及算法导论。不知这些是否是有针对ACM的系统教材,始终在这偌大的书籍中感到彷徨。但我觉得一方面它们倾向于理论证明、缺乏实战性,当时总是希望有位知识渊博的学者能带着我走。可这一切只是天方夜谭,更多的只能希冀在自己的身上。暑假集训从早上9点到下午5点,中间吃饭睡觉花掉3个小时左右,一天有6个小时上课时间,也许这段时间的确不是很长,每上五天课便会放假一天。看似好轻松,然而过于集中精力死盯这电脑屏幕,久而久之会有突如其来的疲倦。如果您想要从一个新手改造成一个合格的队员,你所感到的便是你的疯狂。引入ACM的历史,然后便是三道都是A+B,而且有样例程序培训,开始的第一节莫过于热身。这不仅能带给我们激情和勇气,同时看似基础性的东西却往往是胜败的关键点,使得我们不可松懈。接着便是从最简单的算法开始介绍,依次是:线性表,栈,队列,枚举法,递推法,递归法,分治法,树,搜索,图论的相关知识,并查集,动态规划,大数问题,字符串问

题。线性表,栈,队列:都有顺序结构和链式结构;栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出"的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。而这三者都是来自数据结构的知识,数据结构数据结构是介于数学、计算机硬件和计算机软件三者之间的一门核心课程。数据结构这一门课的内容不仅是一般程序设计(特别是非数值性程序设计)的基础,而且是设计和实现编译程序、操作系统、数据库系统及其他系统程序的重要基础。同时这门课程也是非常难学,需要我们花费更多的功夫。对于ACM的竞赛,更多的是注重于你对题目的灵活运用,采取比较简便的方法,所以便引入了枚举法,递推法,递归法,分治法,动态规划等技巧性较强的专门课程。复杂的ACM竞赛题往往蕴藏着精深的数学道理,需要的是数学知识的结合,学以灵活变通。就是这样才让人感觉到它是种让人从粗浅走向智慧,从蒙昧走向文明,从低级走向高级,从不完善走向完善的艰难历程。除了对这些学术上的专业注重,然而也需要学习英语知识,大多数的竞赛题目是英文,为了更加趋于国际化,英语也成为国际的交流语言,所以学习英语义不容辞,不可推卸。通过以上报告间隙,我结合自身学习实际,进行了客观的对比与反思。在今后的学生涯中,我要查漏补缺,通过学习来完善自身专业素养,努力为自己的梦想实践。

动态规划讲解大全(含例题及答案)

动态规划讲解大全 动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。1957年出版了他的名著Dynamic Programming,这是该领域的第一本著作。 动态规划问世以来,在经济管理、生产调度、工程技术和最优控制等方面得到了广泛的应用。例如最短路线、库存管理、资源分配、设备更新、排序、装载等问题,用动态规划方法比用其它方法求解更为方便。 虽然动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视为多阶段决策过程,也可以用动态规划方法方便地求解。 动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不象前面所述的那些搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。因此读者在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。我们也可以通过对若干有代表性的问题的动态规划算法进行分析、讨论,逐渐学会并掌握这一设计方法。 基本模型 多阶段决策过程的最优化问题。 在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。当然,各个阶段决策的选取不是任意确定的,它依赖于当前面临的状态,又影响以后的发展,当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线,如图所示:(看词条图) 这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题就称为多阶段决策问题。 记忆化搜索 给你一个数字三角形, 形式如下: 1 2 3 4 5 6 7 8 9 10 找出从第一层到最后一层的一条路,使得所经过的权值之和最小或者最大. 无论对与新手还是老手,这都是再熟悉不过的题了,很容易地,我们写出状态转移方程:f(i, j)=a[i, j] + min{f(i+1, j),f(i+1, j + 1)} 对于动态规划算法解决这个问题,我们根据状态转移方程和状态转移方向,比较容易地写出动态规划的循环表示方法。但是,当状态和转移非常复杂的时候,也许写出循环式的动态规划就不是那么

ACM动态规划问题简易模板(C++可编译)

1、0-1背包 #include #include //背包问题 /* 测试数据: 输入: 8 23 8 4 5 1 6 6 7 3 7 8 3 3 4 9 6 2 输出: 1 0 1 0 1 0 1 1 */ int num,c; int v[10]; int w[10]; int m[10][30];//设m[i][j],则表示在前i个物品中,背包大小是j的情况下,背包所装东西的最大价值 void knapsack() { int n=num-1; int jmax,i,j; if(w[n]0;i--) { if(w[i]

} } m[0][c]=m[1][c]; if(c>=w[0]) { if(m[0][c]0) x[n]=1; else x[n]=0; } int main() { int i,x[10],j; scanf("%d %d",&num,&c); for(i=0;i

动态规划matlab仿真实例

动态规划在火力分配中的应用 1.问题描述 设有m个目标,目标价值(重要性和危害性)各不相同,用数值A K( K=1, 2, ..m )表示,计划用n枚导弹突袭,导弹击毁目标的概率P= ,其中是常数,取决于导弹的 特性与目标的性质;为向目标发射的导弹数,问题:做出方案使预期的突击效果最大。 2.问题建模 上述问题可以表述为 约束条件为 ( 为非负整数) 3.算法描述 下面通过一个实例说明:设目标数目为4 (m=4),导弹为5 (n=5), 和a K取值情况如下表所示:表1:A k,取值情况 将火力分配可分为4个阶段,每个阶段指标函数为: 可能取值为0,1, 2,3, 4,5,将函数值带人如下表: 表2函数值

k=le ngth(x(1,:)) % x_is nan=~is nan( x); % t_vubm=i nf*on es(size(x)); % 判断决策级数 非空状态矩阵 性能指标中间矩阵 动态规划问题基本方程为: c =0 逐次向前推一级 K=4 K=3 K=2 K=1 ( 只需要求解的最大值然后反推回去就可以获得最优的分配方案 可取等号) 4. Matlab仿真求解 因为与取值为整数,可以采用动态规划的方法,获得的最大值, fun cti on[ p_opt,fval]=d yn prog(x,DecisFu n,SubObjFu n, Tra nsFu n,ObjFun) % 规划问题最小值函数对应的最优方 求解动态

f_opt=nan*ones(size(x)); % 总性能指标矩阵 d_opt=f_opt; % 每步决策矩阵 tmp1=find(x_isnan(:,k)); % 最后一步状态向量 tmp2=length(tmp1); % 最后一步状态个数for i=1:tmp2 u=feval(DecisFun,k,x(tmp1(i),k)); tmp3=length(u);% 决策变量 for j=1:tmp3 % 求出当前状态下所有决策的最小性能指标 tmp=feval(SubObjFun,k,x(tmp1(i),k),u(j)); if tmp <= t_vubm(i,k) %t_vub f_opt(i,k)=tmp; d_opt(i,k)=u(j); t_vubm(i,k)=tmp; end; end; end for ii=k-1:-1:1 tmp10=find(x_isnan(:,ii)); tmp20=length(tmp10); for i=1:tmp20 % 求出当前状态下所有可能的决策 u=feval(DecisFun,ii,x(tmp10(i),ii)); tmp30=length(u) ; for j=1:tmp30 % 求出当前状态下所有决策的最小性能指标 tmp00=feval(SubObjFun,ii,x(tmp10(i),ii),u(j)); % tmp40=feval(TransFun,ii,x(tmp10(i),ii),u(j)); % tmp50=x(:,ii+1)- tmp40; % 找出下一状态在x tmp60=find(tmp50==0) ; if~isempty(tmp60) if nargin<6 % 矩阵不同需要修改 tmp00=tmp00+f_opt(tmp60(1),ii+1); % set the default object value else tmp00=feval(ObjFun,tmp00,f_opt(tmp60(1),ii+1)); end % 当前状态的性能指标 if tmp00<=t_vubm(i,ii) f_opt(i,ii)=tmp00; d_opt(i,ii)=u(j); t_vubm(i,ii)=tmp00; end; end; end; end; end fval=f_opt(:,1); tmp0 = find(~isnan(fval)); fval=fval(tmp0,1); p_opt=[];tmpx=[];tmpd=[];tmpf=[]; 单步性能指标 下一状态 矩阵的位置 nargin 的值,很重要

动态规划经典案例详解(背包问题)

动态规划经典案例详解之背包问题 【摘要】本文主要从动态规划经典案例——背包问题的动态规划设计思路出发,结合具体实例,对动态规划在程序设计中的典型应用以及衍生拓展进行详细分析。 【关键字】动态规划信息学奥赛0/1背包问题 动态规划并非一个算法,而是一种解题的思路,其核心思想是通过使用大量的存储空间把中间结果记录下来,大大减少重复计算的时间,从而提高的程序的执行效率,因为信息学奥林匹克复赛题目的解决程序一般是有时间限制的,对于某些用搜索必然耗费大量时间的题目,动态规划几乎是唯一的选择。但是动态规划并没有一个简单的模型可以套用,对于每个不同的题目都有对应的不同规划思路,我们只能通过对一些动态规划经典案例的学习来训练自己的动态规划思维能力,从而以不变应万变,应付各种复杂的程序设计,本文通过对动态规划经典案例之一的背包问题进行详细阐述,旨在让学生了解动态规划和搜索的不同设计思路以及动态规划的优越性。 【原型例题】 从n个物品中选取装入背包的物品,每件物品i的重量为wi,价值为pi。求使物品价值最高的选取方法。 【输入文件】 第一行一个数c,为背包容量。 第二行一个数n,为物品数量 第三行n个数,以空格间隔,为n个物品的重量 第四行n个数,以空格间隔,为n个物品的价值 【输出文件】 能取得的最大价值。 【分析】 初看这类问题,第一个想到的会是贪心,但是贪心法却无法保证一定能得到最优解,看以下实例: 贪心准则1:从剩余的物品中,选出可以装入背包的价值最大的物品,利用这种规则,价值最大的物品首先被装入(假设有足够容量),然后是下一个价值最大的物品,如此继续下去。这种策略不能保证得到最优解。例如,考虑n=2,w=[100,10,10],p=[20,15,15],c=105。当利用价值贪婪准则时,获得的解为x=[1,0,0],这种方案的总价值为20。而最优解为[0,1,1],其总价值为30。 贪心准则2:从剩下的物品中选择可装入背包的重量最小的物品。虽然这种规则对于前面的例子能产生最优解,但在一般情况下则不一定能得到最优解。考虑n=2,w=[10,20], p=[5,100],c=25。当利用重量贪婪策略时,获得的解为x=[1,0],比最优解[0,1]要差。

ACM竞赛要掌握的知识

ACM竞赛要掌握的知识 图论 路径问题 最短路径 0/1边权最短路径 BFS 非负边权最短路径 Dijkstra 可以用Dijkstra解决的问题的特征 负边权最短路径 Bellman-Ford Bellman-Ford的Yen-氏优化 差分约束系统 Floyd 广义路径问题 传递闭包 极小极大距离/ 极大极小距离 Euler Path / Tour 圈套圈算法 混合图的Euler Path / Tour Hamilton Path / Tour 特殊图的Hamilton Path / Tour 构造 生成树问题 最小生成树 第k小生成树 最优比率生成树 0/1分数规划 度限制生成树 连通性问题 强大的DFS算法 无向图连通性 割点 割边 二连通分支 有向图连通性 强连通分支 2-SAT 最小点基 有向无环图 拓扑排序 有向无环图与动态规划的关系 二分图匹配问题 一般图问题与二分图问题的转换思路

最大匹配 有向图的最小路径覆盖 0 / 1矩阵的最小覆盖 完备匹配 最优匹配 网络流问题 网络流模型的简单特征和与线性规划的关系最大流最小割定理 最大流问题 有上下界的最大流问题 循环流 最小费用最大流/ 最大费用最大流 弦图的性质和判定 组合数学 解决组合数学问题时常用的思想 逼近 递推/ 动态规划 概率问题 Polya定理 计算几何/ 解析几何 计算几何的核心:*积/ 面积 解析几何的主力:复数 基本形 点 直线,线段 多边形 凸多边形/ 凸包 凸包算法的引进,卷包裹法 Graham扫描法 水平序的引进,共线凸包的补丁 完美凸包算法 相关判定 两直线相交 两线段相交 点在任意多边形内的判定 点在凸多边形内的判定 经典问题 最小外接圆 近似O(n)的最小外接圆算法 点集直径 旋转卡壳,对踵点

牛人的ACM-POJ的题型分类总结!

主流算法: ? 1.搜索//回溯 ? 2.DP(动态规划) ? 3.贪心 ? 4.图论//Dijkstra、最小生成树、网络流 ? 5.数论//解模线性方程 ? 6.计算几何//凸壳、同等安置矩形的并的面积与周长 ?7.组合数学//Polya定理 ?8.模拟 ?9.数据结构//并查集、堆 ?10.博弈论 1、排序 1423,1694, 1723, 1727, 1763, 1788, 1828, 1838, 1840, 2201, 2376, 2377, 2380,1318, 1877, 1928, 1971, 1974, 1990, 2001, 2002, 2092, 2379, 1002(需要字符处理,排序用快排即可) 1007(稳定的排序) 2159(题意较难懂) 2231 2371(简单排序) 2388(顺序统计算法) 2418(二叉排序树) 2、搜索、回溯、遍历 1022 1111 1118 1129 1190 1562 1564 1573 1655 2184 2225 2243 2312 2362 2378 2386 1010,1011,1018,1020,1054,1062,1256,1321,1363,1501, 1650,1659,1664,1753,2078,2083,2303,2310,2329 简单:1128,1166, 1176, 1231, 1256, 1270, 1321, 1543, 1606, 1664, 1731, 1742, 1745,1847, 1915, 1950, 2038, 2157, 2182, 2183, 2381, 2386, 2426, 不易:1024, 1054, 1117, 1167, 1708, 1746, 1775, 1878, 1903, 1966, 2046, 2197, 2349, 推荐:1011,1190, 1191, 1416, 1579, 1632, 1639, 1659, 1680, 1683, 1691, 1709, 1714,1753, 1771, 1826, 1855, 1856, 1890, 1924, 1935, 1948, 1979, 1980, 2170,2288, 2331, 2339, 2340,1979(和迷宫类似)1980(对剪枝要求较高) 3、历法 1008 2080 (这种题要小心) 4、枚举 1012,1046, 1387, 1411, 2245, 2326, 2363, 2381,1054(剪枝要求较高),1650 (小数的精度问题) 5、数据结构的典型算法 容易:1182, 1656, 2021, 2023, 2051, 2153, 2227, 2236, 2247, 2352, 2395, 不易:1145, 1177, 1195, 1227, 1661, 1834, 推荐:1330, 1338, 1451, 1470, 1634, 1689, 1693, 1703, 1724, 1988, 2004, 2010, 2119, 2274, 1125(弗洛伊德算法) ,2421(图的最小生成树) 6、动态规划 1037 A decorative fence、 1050 To the Max、 1088 滑雪、 1125 Stockbroker Grapevine、 1141 Brackets Sequence、

动态规划典型例题

1、单调递增最长子序列 描述 求一个字符串的最长递增子序列的长度 如:dabdbf最长递增子序列就是abdf,长度为4 输入 第一行一个整数0

2、最长公共子序列 描述 如题,需要写一个程序,得出最长公共子序列。 tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则S 称为已知序列的最长公共子序列。 输入 第一行给出一个整数N(0

3、括号匹配 时间限制:1000 ms | 内存限制:65535 KB 描述 给你一个字符串,里面只包含"(",")","[","]"四种符号,请问你需要至少添加多少个括号才能使这些括号匹配起来。 如: []是匹配的 ([])[]是匹配的 ((]是不匹配的 ([)]是不匹配的 输入 第一行输入一个正整数N,表示测试数据组数(N<=10) 每组测试数据都只有一行,是一个字符串S,S中只包含以上所说的四种字符, S的长度不超过100 输出 对于每组测试数据都输出一个正整数,表示最少需要添加的括号的数量。每组 测试输出占一行 样例输入 4 [] ([])[] ((] ([)] 样例输出 3 2

动态规划matlab仿真实例

动态规划在火力分配中的应用。 1.问题描述 设有m个目标,目标价值(重要性和危害性)各不相同,用数值A K(K=1,2,..m)表示,计划用n枚导弹突袭,导弹击毁目标的概率P K=,其中是常数,取决于导弹的特性与目标的性质;为向目标发射的导弹数,问题:做出方案使预期的突击效果最大。 2.问题建模 上述问题可以表述为 约束条件为 (为非负整数) 3.算法描述 下面通过一个实例说明:设目标数目为4(m=4),导弹为5(n=5),和a K取值情况如下表所示: 表1:A k 取值情况 目标K 1 2 3 4 8 7 6 3 0.2 0.3 0.5 0.9 将火力分配可分为4个阶段,每个阶段指标函数为:

可能取值为0,1,2,3,4,5,将函数值带人如下表: 表2 函数值 u 0 0 0 0 0 1 1.45 1.81 2.36 1.79 2 2.64 3.16 3.79 2.51 3 3.61 4.15 4.66 2.81 4 4.41 4.89 5.19 2.93 5 5.0 6 5.44 5.51 2.97 动态规划问题基本方程为: c =0 逐次向前推一级 K=4 K=3 K=2 K=1 () 只需要求解的最大值然后反推回去就可以获得最优的分配方案

4.Matlab仿真求解 因为与取值为整数,可以采用动态规划的方法,获得的最大值,对应的

最优方案 function[p_opt,fval]=dynprog(x,DecisFun,SubObjFun,TransFun,ObjFun) %求解动态规划问题最小值函数 k=length(x(1,:)) %判断决策级数 x_isnan=~isnan(x); % 非空状态矩阵 t_vubm=inf*ones(size(x)); % 性能指标中间矩阵 f_opt=nan*ones(size(x)); % 总性能指标矩阵 d_opt=f_opt; %每步决策矩阵 tmp1=find(x_isnan(:,k)); % 最后一步状态向量 tmp2=length(tmp1); % 最后一步状态个数 for i=1:tmp2 u=feval(DecisFun,k,x(tmp1(i),k)); tmp3=length(u);%决策变量 for j=1:tmp3 % 求出当前状态下所有决策的最小性能指标 tmp=feval(SubObjFun,k,x(tmp1(i),k),u(j)); if tmp <= t_vubm(i,k) %t_vub f_opt(i,k)=tmp; d_opt(i,k)=u(j); t_vubm(i,k)=tmp; end; end; end for ii=k-1:-1:1 tmp10=find(x_isnan(:,ii)); tmp20=length(tmp10); for i=1:tmp20 %求出当前状态下所有可能的决策 u=feval(DecisFun,ii,x(tmp10(i),ii)); tmp30=length(u) ; for j=1:tmp30 % 求出当前状态下所有决策的最小性能指标 tmp00=feval(SubObjFun,ii,x(tmp10(i),ii),u(j)); % 单步性能指标 tmp40=feval(TransFun,ii,x(tmp10(i),ii),u(j)); % 下一状态 tmp50=x(:,ii+1)-tmp40; % 找出下一状态在 x 矩阵的位置 tmp60=find(tmp50==0) ; if~isempty(tmp60) if nargin<6 %矩阵不同需要修改nargin的值,很重要 tmp00=tmp00+f_opt(tmp60(1),ii+1); % set the default object value else tmp00=feval(ObjFun,tmp00,f_opt(tmp60(1),ii+1)); end %当前状态的性能指标 if tmp00<=t_vubm(i,ii) f_opt(i,ii)=tmp00; d_opt(i,ii)=u(j);

动态规划习题讲解

第七章动态规划 规划问题的最终目的就是确定各决策变量的取值,以使目标函数达到极大或极小。在线性规划和非线性规划中,决策变量都是以集合的形式被一次性处理的;然而,有时我们也会面对决策变量需分期、分批处理的多阶段决策问题。所谓多阶段决策问题是指这样一类活动过程:它可以分解为若干个互相联系的阶段,在每一阶段分别对应着一组可供选取的决策集合;即构成过程的每个阶段都需要进行一次决策的决策问题。将各个阶段的决策综合起来构成一个决策序列,称为一个策略。显然,由于各个阶段选取的决策不同,对应整个过程可以有一系列不同的策略。当过程采取某个具体策略时,相应可以得到一个确定的效果,采取不同的策略,就会得到不同的效果。多阶段的决策问题,就是要在所有可能采取的策略中选取一个最优的策略,以便得到最佳的效果。动态规划(dynamic programming)同前面介绍过的各种优化方法不同,它不是一种算法,而是考察问题的一种途径。动态规划是一种求解多阶段决策问题的系统技术,可以说它横跨整个规划领域(线性规划和非线性规划)。当然,由于动态规划不是一种特定的算法,因而它不象线性规划那样有一个标准的数学表达式和明确定义的一组规则,动态规划必须对具体问题进行具体的分析处理。在多阶段决策问题中,有些问题对阶段的划分具有明显的时序性,动态规划的“动态”二字也由此而得名。动态规划的主要创始人是美国数学家贝尔曼(Bellman)。20世纪40年代末50年代初,当时在兰德公司(Rand Corporation)从事研究工作的贝尔曼首先提出了动态规划的概念。1957年贝尔曼发表了数篇研究论文,并出版了他的第一部著作《动态规划》。该著作成为了当时唯一的进一步研究和应用动态规划的理论源泉。1961年贝尔曼出版了他的第二部著作,并于1962年同杜瑞佛思(Dreyfus)合作出版了第三部著作。在贝尔曼及其助手们致力于发展和推广这一技术的同时,其他一些学者也对动态规划的发展做出了重大的贡献,其中最值得一提的是爱尔思(Aris)和梅特顿(Mitten)。爱尔思先后于1961年和1964年出版了两部关于动态规划的著作,并于1964年同尼母霍思尔(Nemhauser)、威尔德(Wild)一道创建了处理分枝、循环性多阶段决策系统的一般性理论。梅特顿提出了许多对动态规划后来发展有着重要意义的基础性观点,并且对明晰动态规划路径的数学性质做出了巨大的贡献。 动态规划在工程技术、经济管理等社会各个领域都有着广泛的应用,并且获得了显著的效果。在经济管理方面,动态规划可以用来解决最优路径问题、资源分配问题、生产调度问题、库存管理问题、排序问题、设备更新问题以及生产过程最优控制问题等,是经济管理中一种重要的决策技术。许多规划问题用动态规划的方法来处理,常比线性规划或非线性规划更有效。特别是对于离散的问题,由于解析数学无法发挥作用,动态规划便成为了一种非常有用的工具。 动态规划可以按照决策过程的演变是否确定分为确定性动态规划和随机性动态规划;也可以按照决策变量的取值是否连续分为连续性动态规划和离散性动态规划。本教材主要介绍动态规划的基本概念、理论和方法,并通过典型的案例说明这些理论和方法的应用。 §7.1 动态规划的基本理论 1.1多阶段决策过程的数学描述 有这样一类活动过程,其整个过程可分为若干相互联系的阶段,每一阶段都要作出相应的决策,以使整个过程达到最佳的活动效果。任何一个阶段(stage,即决策点)都是由输入(input)、决策(decision)、状态转移律(transformation function)和输出(output)构成的,如图7-1(a)所示。其中输入和输出也称为状态(state),输入称为输入状态,输出称为输出状态。

DP类型各题总结-acm

最大连续子序列 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11540 Accepted Submission(s): 4856 还需要输出该子序列的第一个和最后一个元素。 对每个测试用例,在1行里输出最大和、最大连续子序列的第一个和最后一个元 素,中间用空格分隔。如果最大连续子序列不唯一,则输出序号i和j最小的那个(如输入样例的第2、3组)。若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。 思路:一路加如果sum变成小于0了从当前位置重新新开始加(小于0的话就对整个段没有贡献了而且会使整个段的和变小) #include int main() { int n,i,a[10005],start,end,sum,max,sta,flag,cnt; while(1) { cnt=0; sum=0;max=-1;flag=1; scanf("%d",&n); if(n==0) return 0; for(i=0;i

(整理)ACM大量习题题库及建议培养计划.

//别人总结的,确实很多,但有信心就能学完! 一.基本算法: (1)枚举.(poj1753,poj2965) (2)贪心.(poj1328,poj2109,poj2586) (3)递归和分治法. (4)递推. (5)构造法.(poj3295) (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法: (1)图的深度优先遍历和广度优先遍历. (2)最短路径算法.(dijkstra,bellman-ford,floyd,heap+dijkstra) (poj1860,poj3259,poj1062,poj2253,poj1125,poj2240) (3)最小生成树算法.(prim,kruskal) (poj1789,poj2485,poj1258,poj3026) (4)拓扑排序.(poj1094) (5)二分图的最大匹配(匈牙利算法).(poj3041,poj3020) (6)最大流的增广路算法(KM算法).(poj1459,poj3436) 三.数据结构. (1)串.(poj1035,poj3080,poj1936) (2)排序(快排、归并排(与逆序数有关)、堆排).(poj2388,poj2299) (3)简单并查集的应用. (4)哈希表和二分查找等高效查找法.(数的Hash,串的Hash) (poj3349,poj3274,POJ2151,poj1840,poj2002,poj2503) (5)哈夫曼树.(poj3253) (6)堆. (7)trie树(静态建树、动态建树).(poj2513) 四.简单搜索 (1)深度优先搜索.(poj2488,poj3083,poj3009,poj1321,poj2251) (2)广度优先搜索.(poj3278,poj1426,poj3126,poj3087.poj3414) (3)简单搜索技巧和剪枝.(poj2531,poj1416,poj2676,1129) 五.动态规划 (1)背包问题. (poj1837,poj1276) (2)型如下表的简单DP(可参考lrj的书page149): 1.E[j]=opt{D+w(i,j)} (poj3267,poj1836,poj1260,poj2533) 2.E[i,j]=opt{D[i-1,j]+xi,D[i,j-1]+yj,D[i-1][j-1]+zij} (最长公共子序列) (poj3176,poj1080,poj1159) 3.C[i,j]=w[i,j]+opt{C[i,k-1]+C[k,j]}.(最优二分检索树问题) 六.数学 (1)组合数学: 1.加法原理和乘法原理. 2.排列组合. 3.递推关系. (POJ3252,poj1850,poj1019,poj1942) (2)数论.

动态规划算法原理与的应用

动态规划算法原理 及其应用研究 2012年5月20日摘要:动态规划是解决最优化问题的基本方法,本文介绍了

动态规划的基本思想和基本步骤,并通过几个实例的分析,研究了利用动态规划设计算法的具体途径。关键词:动态规划多阶段决策 1.引言 规划问题的最终目的就是确定各决策变量的取值,以使目标函数达到极大或极小。在线性规划和非线性规划中,决策变量都是以集合的形式被一次性处理的;然而,有时我们也会面对决策变量需分期、分批处理的多阶段决策问题。所谓多阶段决策问题是指这样一类活动过程:它可以分解为若干个互相联系的阶段,在每一阶段分别对应着一组可供选取的决策集合;即构成过程的每个阶段都需要进行一次决策的决策问题。将各个阶段的决策综合起来构成一个决策序列,称为一■ 个策略。显然,由于各个阶段选取的决策不同,对应整个过程可以有一系列不同的策略。当过程采取某个具体策略时,相应可以得到一个确定的效果,采取不同的策略,就会得到不同的效果。多阶段的决策问题,就是要在所有可能采取的策略中选取一个最优的策略,以便得到最佳的效果。动态规划是一种求解多阶段决策问题的系统技术,可以说它横跨整个规划领域(线性规划和非线性规划)。在多阶段决策问题中,有些问题对阶段的划分具有明显的时序性,动态规划的“动态”二字也由此而得名。动态规划的主要创始人是美国数学家贝尔曼(Bellman)。20世纪40年代末50年代初,当时在兰德公司(Rand Corporation)从事研究工作的贝尔曼首先提出了动态规划的概念。1957年贝尔曼发表了数篇研究论文,并出版了他的第一部著作《动态规划》。该著作成为了当时唯一的进一步研究和应用动态规划的理论源泉。在贝尔曼及其助手们致力于发展和推广这一技术的同时,其他一些学者也对动态规划的发展做出了重大的贡献,其中最值得一提的是爱尔思(Aris)和梅特顿(Mitten )。爱尔思先后于1961年和1964年出版了两部 关于动态规划的著作,并于1964年同尼母霍思尔(Nemhause)、威尔德(Wild)一道创建了处理分枝、循环性多阶段决策系统的一般性理论。梅特顿提出了许多对动态规划后来发展有着重要意义的基础性观点,并且对明晰动态规划路径的数学性质做出了巨大的贡献。 动态规划问世以来,在工程技术、经济管理等社会各个领域都有着广泛的应用,并且获得了显著的效果。在经济管理方面,动态规划可以用来解决最优路径

相关文档
最新文档