(总结一)poj简单动态规划
(总结一)poj简单动态规划

例1:求一维数组中连续数之和的最大值。
代码:#include<iostream>using namespace std;int a[100];//记录一维数组int res[100];//res[i]表示以第i个数为末尾的连续数之和的最大值int main(){int i,n,max;while(1){cin>>n;if(!n) break;memset(res,0,sizeof(a)),max=-1270000;for(i=0;i<n;i++){cin>>a[i];res[i]=a[i];if(i>0 && res[i-1]>0) res[i]+=res[i-1];//动态规划法if(res[i]>max) max=res[i];//打擂法}cout<<max<<endl;}return 0;}例2(poj1050):求二维数组中子矩阵之和的最大值。
(例1的拓展)代码:#include<iostream>using namespace std;int a[101][101];//记录二维数组int sum[101][101];//sum[i][j]表示第j列前i行的数之和int res[101][101][101];//res[i1][i2][j]表示从第i1行到第i2行,以第j个数为末尾的连续数之和的最大值int main(){int i,i1,i2,j,n,temp,max;while(1){cin>>n;if(!n) break;memset(sum,0,sizeof(sum)),memset(res,0,sizeof(res));for(i=1;i<=n;i++)for(j=1;j<=n;j++){cin>>a[i][j];//输入二维数组sum[i][j]=sum[i-1][j]+a[i][j];//求第j列前i行之和}max=-1270000;for(i1=1;i1<=n;i1++)//类似一维数组求最大和的方法,将一重循环改为三重循环for(i2=i1;i2<=n;i2++)for(j=1;j<=n;j++){res[i1][i2][j]=sum[i2][j]-sum[i1-1][j];//相当于一维数组中的第j 个数if(res[i1][i2][j-1]>0) res[i1][i2][j]+=res[i1][i2][j-1];if(res[i1][i2][j]>max) max=res[i1][i2][j];}cout<<max<<endl;}return 0;}例3(poj1458):求最长公共子序列的长度。
POJ 题目整理

初期:一.基本算法:(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)数论.1.素数与整除问题2.进制位.3.同余模运算.(poj2635, poj3292,poj1845,poj2115)(3)计算方法.1.二分法求解单调函数相关知识.(poj3273,poj3258,poj1905,poj3122)七.计算几何学.(1)几何公式.(2)叉积和点积的运用(如线段相交的判定,点到线段的距离等). (poj2031,poj1039)(3)多边型的简单算法(求面积)和相关判定(点在多边型内,多边型是否相交)(poj1408,poj1584)(4)凸包. (poj2187,poj1113)中级:一.基本算法:(1)C++的标准模版库的应用. (poj3096,poj3007)(2)较为复杂的模拟题的训练(poj3393,poj1472,poj3371,poj1027,poj2706)二.图算法:(1)差分约束系统的建立和求解. (poj1201,poj2983)(2)最小费用最大流(poj2516,poj2516,poj2195)(3)双连通分量(poj2942)(4)强连通分支及其缩点.(poj2186)(5)图的割边和割点(poj3352)(6)最小割模型、网络流规约(poj3308, )三.数据结构.(1)线段树. (poj2528,poj2828,poj2777,poj2886,poj2750)(2)静态二叉检索树. (poj2482,poj2352)(3)树状树组(poj1195,poj3321)(4)RMQ. (poj3264,poj3368)(5)并查集的高级应用. (poj1703,2492)(6)KMP算法. (poj1961,poj2406)四.搜索(1)最优化剪枝和可行性剪枝(2)搜索的技巧和优化 (poj3411,poj1724)(3)记忆化搜索(poj3373,poj1691)五.动态规划(1)较为复杂的动态规划(如动态规划解特别的施行商问题等) (poj1191,poj1054,poj3280,poj2029,poj2948,poj1925,poj3034)(2)记录状态的动态规划. (POJ3254,poj2411,poj1185)(3)树型动态规划(poj2057,poj1947,poj2486,poj3140)六.数学(1)组合数学:1.容斥原理.2.抽屉原理.3.置换群与Polya定理(poj1286,poj2409,poj3270,poj1026).4.递推关系和母函数.(2)数学.1.高斯消元法(poj2947,poj1487, poj2065,poj1166,poj1222)2.概率问题. (poj3071,poj3440)3.GCD、扩展的欧几里德(中国剩余定理) (poj3101)(3)计算方法.1.0/1分数规划. (poj2976)2.三分法求解单峰(单谷)的极值.3.矩阵法(poj3150,poj3422,poj3070)4.迭代逼近(poj3301)(4)随机化算法(poj3318,poj2454)(5)杂题. (poj1870,poj3296,poj3286,poj1095)七.计算几何学.(1)坐标离散化.(2)扫描线算法(例如求矩形的面积和周长并,常和线段树或堆一起使用).(poj1765,poj1177,poj1151,poj3277,poj2280,poj3004)(3)多边形的内核(半平面交)(poj3130,poj3335)(4)几何工具的综合应用.(poj1819,poj1066,poj2043,poj3227,poj2165,poj3429)高级:一.基本算法要求:(1)代码快速写成,精简但不失风格(poj2525,poj1684,poj1421,poj1048,poj2050,poj3306)(2)保证正确性和高效性. poj3434二.图算法:(1)度限制最小生成树和第K最短路. (poj1639)(2)最短路,最小生成树,二分图,最大流问题的相关理论(主要是模型建立和求解) (poj3155, poj2112,poj1966,poj3281,poj1087,poj2289,poj3216,poj2446) (3)最优比率生成树. (poj2728)(4)最小树形图(poj3164)(5)次小生成树.(6)无向图、有向图的最小环三.数据结构.(1)trie图的建立和应用. (poj2778)(2)LCA和RMQ问题(LCA(最近公共祖先问题) 有离线算法(并查集+dfs) 和在线算法(RMQ+dfs)).(poj1330)(3)双端队列和它的应用(维护一个单调的队列,常常在动态规划中起到优化状态转移的目的).(poj2823)(4)左偏树(可合并堆).(5)后缀树(非常有用的数据结构,也是赛区考题的热点). (poj3415,poj3294)四.搜索(1)较麻烦的搜索题目训练(poj1069,poj3322,poj1475,poj1924,poj2049,poj3426)(2)广搜的状态优化:利用M进制数存储状态、转化为串用hash表判重、按位压缩存储状态、双向广搜、A*算法. (poj1768,poj1184,poj1872,poj1324,poj2046,poj1482)(3)深搜的优化:尽量用位运算、一定要加剪枝、函数参数尽可能少、层数不易过大、可以考虑双向搜索或者是轮换搜索、IDA*算法.(poj3131,poj2870,poj2286)五.动态规划(1)需要用数据结构优化的动态规划. (poj2754,poj3378,poj3017)(2)四边形不等式理论.(3)较难的状态DP(poj3133)六.数学(1)组合数学.1.MoBius反演(poj2888,poj2154)2.偏序关系理论.(2)博奕论.1.极大极小过程(poj3317,poj1085)2.Nim问题.七.计算几何学.(1)半平面求交(poj3384,poj2540)(2)可视图的建立(poj2966)(3)点集最小圆覆盖.(4)对踵点(poj2079)八.综合题.(poj3109,poj1478,poj1462,poj2729,poj2048,poj3336,poj3315,poj2148,poj1263) 以及补充Dp状态设计与方程总结1.不完全状态记录<1>青蛙过河问题<2>利用区间dp2.背包类问题<1> 0-1背包,经典问题<2>无限背包,经典问题<3>判定性背包问题<4>带附属关系的背包问题<5> + -1背包问题<6>双背包求最优值<7>构造三角形问题<8>带上下界限制的背包问题(012背包)3.线性的动态规划问题<1>积木游戏问题<2>决斗(判定性问题)<3>圆的最大多边形问题<4>统计单词个数问题<5>棋盘分割<6>日程安排问题<7>最小逼近问题(求出两数之比最接近某数/两数之和等于某数等等)<8>方块消除游戏(某区间可以连续消去求最大效益)<9>资源分配问题<10>数字三角形问题<11>漂亮的打印<12>邮局问题与构造答案<13>最高积木问题<14>两段连续和最大<15>2次幂和问题<16>N个数的最大M段子段和<17>交叉最大数问题4.判定性问题的dp(如判定整除、判定可达性等)<1>模K问题的dp<2>特殊的模K问题,求最大(最小)模K的数<3>变换数问题5.单调性优化的动态规划<1>1-SUM问题<2>2-SUM问题<3>序列划分问题(单调队列优化)6.剖分问题(多边形剖分/石子合并/圆的剖分/乘积最大)<1>凸多边形的三角剖分问题<2>乘积最大问题<3>多边形游戏(多边形边上是操作符,顶点有权值)<4>石子合并(N^3/N^2/NLogN各种优化)7.贪心的动态规划<1>最优装载问题<2>部分背包问题<3>乘船问题<4>贪心策略<5>双机调度问题Johnson算法8.状态dp<1>牛仔射击问题(博弈类)<2>哈密顿路径的状态dp<3>两支点天平平衡问题<4>一个有向图的最接近二部图9.树型dp<1>完美服务器问题(每个节点有3种状态)<2>小胖守皇宫问题<3>网络收费问题<4>树中漫游问题<5>树上的博弈<6>树的最大独立集问题<7>树的最大平衡值问题<8>构造树的最小环转一个搞ACM需要的掌握的算法.要注意,ACM的竞赛性强,因此自己应该和自己的实际应用联系起来.适合自己的才是好的,有的人不适合搞算法,喜欢系统架构,因此不要看到别人什么就眼红, 发挥自己的长处,这才是重要的.第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来.1.最短路(Floyd、Dijstra,BellmanFord)2.最小生成树(先写个prim,kruscal要用并查集,不好写)3.大数(高精度)加减乘除4.二分查找. (代码可在五行以内)5.叉乘、判线段相交、然后写个凸包.6.BFS、DFS,同时熟练hash表(要熟,要灵活,代码要简)7.数学上的有:辗转相除(两行内),线段交点、多角形面积公式.8. 调用系统的qsort, 技巧很多,慢慢掌握.9. 任意进制间的转换第二阶段:练习复杂一点,但也较常用的算法。
POJ_动态规划

题目:动态规划_2479 AC率:6120/20257题意解释:给定n个数,求两段连续不重叠子段的最大和。
比如1 -1 2 2 3 -3 4 -4 5 -5结果就是{2,2,3,-3,4} 和{5},也就是两者的和13。
选题原因:此题是对动态规划中的一个基础知识点求最大字段和的一个简单应用,难度不太大,比较具有代表性,是基础题型。
求最大字段和的方法有很多,但DP是最高效的,时间效率为O(n)。
有关求最大字段和的详细介绍参见王晓东《算法设计与分析》第三版59页相关部分。
这里仅附上求最大字段和的状态转移方程:b[j] = max {b[j-1] + a[j], a[j]}, 1 <= j <= n。
解题思路:先对数字串从左向右依次求出每段的连续子序列的最大字段和,并将其存入数组array[i]中(i为对应位置),再从右向左用同样的方法求一次最大字段和,并将每个子段i~n的和与对应的另一半1~i-1相加,求出最大值。
也就是对每个位置i来说,求出[1~i-1]的最大子段和以及[i~n]的最大子段和,再相加起来,求最大的一个就行了。
与基础的求最大字段和不同的是,该题需要对每个子段记录其最大和,即存入数组array[i]中。
程序代码:#include <stdio.h>int array[50001], num[50001];const int MIN = -999999999;int main(){int tcase, n;scanf("%d", &tcase);int tmp, ans, i, sum;while(tcase--){scanf("%d", &n);tmp = MIN; sum = 0;for(i = 1; i <= n; i++){scanf("%d", &num[i]);sum += num[i];if(sum > tmp)tmp = sum;array[i] = tmp; // 记录每个字段的最大值。
《动态规划》课件

xx年xx月xx日
• 动态规划概述 • 动态规划的基本概念 • 动态规划的求解方法 • 动态规划的应用实例 • 动态规划的优化技巧 • 动态规划的总结与展望
目录
01
动态规划概述
定义与特点
定义
动态规划是一种通过将原问题分解为 相互重叠的子问题,并存储子问题的 解以避免重复计算的方法。
特点
动态规划适用于具有重叠子问题和最 优子结构的问题,通过将问题分解为 子问题,可以找到最优解。
动态规划的适用范围
最优化问题
01
动态规划适用于解决最优化问题,如最大/最小化问题、决策问
题等。
子问题重叠
02
动态规划适用于子问题重叠的情况,即子问题之间存在共享状
态或参数。
递归关系
03
动态规划适用于具有递归关系的问题,可以通过递归方式求解
机器调度问题
总结词
动态规划可以应用于机器调度问题,以确定最优的调度方案,满足生产需求并降低成本 。
详细描述
机器调度问题是一个经典的优化问题,涉及到如何分配任务到机器上,以最小化成本或 最大化效率。通过动态规划,可以将机器调度问题分解为一系列子问题,如确定每个任 务的调度顺序、分配机器等,并逐个求解子问题的最优解,最终得到整个调度方案的最
VS
详细描述
记忆化搜索法是一种优化技术,通过存储 已解决的子问题的解,避免重复计算,提 高求解效率。这种方法适用于子问题数量 较少且相互独立的情况。
04
动态规划的应用实例
最短路径问题
总结词
通过动态规划解决最短路径问题,可以找到 从起点到终点的最短路径。
详细描述
在图论中,最短路径问题是一个经典的优化 问题,旨在找到从起点到终点之间的一条路 径,使得路径上的所有边的权重之和最小。 动态规划是一种有效的解决方法,通过将问 题分解为子问题并存储子问题的解,避免了 重复计算,提高了求解效率。
动态规划总结

动态规划总结动态规划系列内容算是结束了,虽然有关动态规划的知识点还有很多,但是我相信如果深刻掌握并理解了之前我们讲的内容,基本上leetcode 上面90% 以上的动态规划相关问题都可以很好解决。
动态规划就是利用历史记录,来避免我们的重复计算。
而这些历史记录,我们得需要一些变量来保存,一般是用一维数组或者二维数组来保存。
下面我们先来讲下做动态规划题很重要的三个步骤,第一步骤:定义数组元素的含义,上面说了,我们会用一个数组,来保存历史数组,假设用一维数组dp[] 吧。
这个时候有一个非常非常重要的点,就是规定你这个数组元素的含义,例如你的dp[i] 是代表什么意思?第二步骤:找出数组元素之间的关系式,我觉得动态规划,还是有一点类似于我们高中学习时的归纳法的,当我们要计算dp[n] 时,是可以利用dp[n-1],dp[n-2]…..dp[1],来推出dp[n] 的,也就是可以利用历史数据来推出新的元素值,所以我们要找出数组元素之间的关系式,例如dp[n] = dp[n-1] + dp[n-2],这个就是他们的关系式了。
而这一步,也是最难的一步,后面我会讲几种类型的题来说。
第三步骤:找出初始值。
学过数学归纳法的都知道,虽然我们知道了数组元素之间的关系式,例如dp[n] = dp[n-1] + dp[n-2],我们可以通过dp[n-1] 和dp[n-2] 来计算dp[n],但是,我们得知道初始值啊,例如一直推下去的话,会由dp[3] = dp[2] + dp[1]。
而dp[2] 和dp[1] 是不能再分解的了,所以我们必须要能够直接获得dp[2] 和dp[1] 的值,而这,就是所谓的初始值。
由了初始值,并且有了数组元素之间的关系式,那么我们就可以得到dp[n] 的值了,而dp[n] 的含义是由你来定义的,你想求什么,就定义它是什么,这样,这道题也就解出来了。
当然了,要想达到熟能生巧的程度,还是需要多加练习,多思考,多对比,多总结,不然的话,学到的东西很快就会忘记。
动态规划总结经典题目(经典中的经典)

动态规划总结——经典问题总结本文着重讨论状态是如何表示,以及方程是怎样表示的。
当然,还附上关键的,有可能作为模板的代码段。
但有的代码的实现是优化版的。
经典问题总结最长上升子序列(LIS)问题描述如下:设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm。
求最大的m值。
这里采用的是逆向思维的方法,从最后一个开始想起,即先从A[N](A数组是存放数据的数组,下同)开始,则只有长度为1的子序列,到A[N-1]时就有两种情况,如果a[n-1] < a[n] 则存在长度为2的不下降子序列a[n-1],a[n];如果a[n-1] > a[n] 则存在长度为1的不下降子序列a[n-1]或者a[n]。
有了以上的思想,DP方程就呼之欲出了(这里是顺序推的,不是逆序的):DP[I]=MAX(1,DP[J]+1)J=0,1,...,I-1但这样的想法实现起来是)O(n^2)的。
本题还有更好的解法,就是O(n*logn)。
利用了长升子序列的性质来优化,以下是优化版的代码://最长不降子序const int SIZE=500001;int data[SIZE];int dp[SIZE];//返回值是最长不降子序列的最大长度,复杂度O(N*logN)int LCS(int n) { //N是DATA数组的长度,下标从1开始int len(1),low,high,mid,i;dp[1]=data[1];for(i=1;i<=n;++i) {low=1;high=len;while( low<=high ) { //二分mid=(low+high)/2;if( data[i]>dp[mid] ) {low=mid+1;}else {high=mid-1;}}dp[low]=data[i];if( low>len ) {++len;}}return len;}最长公共子序列(LCS)给出两个字符串a, b,求它们的最长、连续的公共字串。
动态规划(完整)ppt课件

3
• Ⅲ --Ⅳ :
B1—C1—T
4
• Ⅱ--Ⅲ--Ⅳ :A2—B1—C1—T
7
• Ⅰ--Ⅱ--Ⅲ --Ⅳ:
•
Q—A2—B1—C1—T
11
•
Q--A3—B1—C1—T
11
•
Q--A3—B2—C2—T
11
最新版整理ppt
3
最短路径
11
4
7
A1
4
2
6
11
47
3 2
Q
A2
4
B1
1
4 76
3
C1
3
B2 3
最新版整理ppt
16
(4)策略和允许策略集合
策略(Policy)也叫决策序列.策略有全过程 策略和 k 部子策略之分,全过程策略是指具 有n 个阶段的全部过程,由依次进行的 n 个 阶段决策构成的决策序列,简称策略,表示
为 p1,n{x1,x2, ,xn}。从 k 阶段到第 n 阶段,
依次进行的阶段决策构成的决策序列称为 k
新分支的创立。
最新版整理ppt
6
• 动态规划将复杂的多阶段决策问题分解为 一系列简单的、离散的单阶段决策问题, 采用顺序求解方法, 通过解一系列小问题 达到求解整个问题目的;
• 动态规划的各个决策阶段不但要考虑本阶 段的决策目标, 还要兼顾整个决策过程的 整体目标, 从而实现整体最优决策.
最新版整理ppt
第七章 动态规划
主要内容:
§7.1多阶段决策问题 §7.2 动态规划的基本概念和基本原理 §7.3 动态规划应用举例
最新版整理ppt
1
例 求解最短路问题
2
Q
4
动态规划总结

动态规划总结终于来到了设计思想中最难,也最有趣的这部分,在去年的google笔试中,7道算法设计题有2道动态规划(Dynamic Programming)。
看了这么久的算法,这部分也是唯⼀感觉到了⽐较难的地⽅,从这篇⽂章开始,将花连续的篇幅来讨论⼀些动态规划的问题。
这包括书上介绍过的计算⼆项式系数,Warshall算法求传递闭包,Floyd算法求完全最短路径,构造最有⼆叉查找树,背包问题和记忆功能。
也包括⼀些其他问题的解题报告(动态规划确实很难,对这⼀章的内容,我将搜索⼀些其他类型的问题来写解题报告,以真正的理解动态规划),例如矩阵连乘,最长公共⼦列,等等。
————————————————————————————————————————————————–1,什么是动态规划(DP)?⾮常重要!,不要认为概念不重要,理解的深刻,你才知道对于什么样的问题去考虑有没有动态规划的⽅法,以及如何去使⽤动态规划。
1)动态规划是运筹学中⽤于求解决策过程中的最优化数学⽅法。
当然,我们在这⾥关注的是作为⼀种算法设计技术,作为⼀种使⽤多阶段决策过程最优的通⽤⽅法。
它是应⽤数学中⽤于解决某类最优化问题的重要⼯具。
2)如果问题是由交叠的⼦问题所构成,我们就可以⽤动态规划技术来解决它,⼀般来说,这样的⼦问题出现在对给定问题求解的递推关系中,这个递推关系包含了相同问题的更⼩⼦问题的解。
动态规划法建议,与其对交叠⼦问题⼀次⼜⼀次的求解,不如把每个较⼩⼦问题只求解⼀次并把结果记录在表中(动态规划也是空间换时间的),这样就可以从表中得到原始问题的解。
关键词:它往往是解决最优化问题滴问题可以表现为多阶段决策(去⽹上查查什么是多阶段决策!)交叠⼦问题:什么是交叠⼦问题,最有⼦结构性质。
动态规划的思想是什么:记忆,空间换时间,不重复求解,由交叠⼦问题从较⼩问题解逐步决策,构造较⼤问题的解。
————————————————————————————————————————————————-关于斐波拉切数列可以作为最简单的⼀个例⼦来解释动态规划的思想,在前⾯讲斐波拉切数列时说过了,不再叙述。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
例1:求一维数组中连续数之和的最大值。
代码:#include<iostream>using namespace std;int a[100];//记录一维数组int res[100];//res[i]表示以第i个数为末尾的连续数之和的最大值int main(){int i,n,max;while(1){cin>>n;if(!n) break;memset(res,0,sizeof(a)),max=-1270000;for(i=0;i<n;i++){cin>>a[i];res[i]=a[i];if(i>0 && res[i-1]>0) res[i]+=res[i-1];//动态规划法if(res[i]>max) max=res[i];//打擂法}cout<<max<<endl;}return 0;}例2(poj1050):求二维数组中子矩阵之和的最大值。
(例1的拓展)代码:#include<iostream>using namespace std;int a[101][101];//记录二维数组int sum[101][101];//sum[i][j]表示第j列前i行的数之和int res[101][101][101];//res[i1][i2][j]表示从第i1行到第i2行,以第j个数为末尾的连续数之和的最大值int main(){int i,i1,i2,j,n,temp,max;while(1){cin>>n;if(!n) break;memset(sum,0,sizeof(sum)),memset(res,0,sizeof(res));for(i=1;i<=n;i++)for(j=1;j<=n;j++){cin>>a[i][j];//输入二维数组sum[i][j]=sum[i-1][j]+a[i][j];//求第j列前i行之和}max=-1270000;for(i1=1;i1<=n;i1++)//类似一维数组求最大和的方法,将一重循环改为三重循环for(i2=i1;i2<=n;i2++)for(j=1;j<=n;j++){res[i1][i2][j]=sum[i2][j]-sum[i1-1][j];//相当于一维数组中的第j 个数if(res[i1][i2][j-1]>0) res[i1][i2][j]+=res[i1][i2][j-1];if(res[i1][i2][j]>max) max=res[i1][i2][j];}cout<<max<<endl;}return 0;}例3(poj1458):求最长公共子序列的长度。
代码:#include<iostream>#include<string>using namespace std;int res[500][500];//res[i][j]表示s1中第i个字符、s2中第j个字符之前的最长公共子序列长度int max(int a,int b){return a>b?a:b;}int main(){int i,j,n1,n2;string s1,s2;while(1){cin>>s1>>s2;memset(res,0,sizeof(res)),n1=s1.length(),n2=s2.length();for(i=0;i<n1;i++)for(j=0;j<n2;j++){if(s1[i]==s2[j]) res[i+1][j+1]=res[i][j]+1;//动态规划法else res[i+1][j+1]=max(res[i][j+1],res[i+1][j]);}cout<<res[n1][n2]<<endl;}return 0;}例4(poj1163):求三角形内可取得的最大和。
#include<iostream>using namespace std;int a[101][101];int res[101][101];//res[i][j]表示从顶端到达位置(i,j)所取得的最大值int Max(int a,int b){return a>b?a:b;}int main(){int i,j,n,max;cin>>n;while(n){for(i=0;i<n;i++)//输入数据for(j=0;j<=i;j++)cin>>a[i][j];res[0][0]=a[0][0];for(i=1;i<n;i++) res[i][0]=res[i-1][0]+a[i][0];//求解边界情况for(i=1;i<n;i++) res[i][i]=res[i-1][i-1]+a[i][i];for(i=2;i<n;i++)//求解一般情况for(j=1;j<i;j++)res[i][j]=Max(res[i-1][j],res[i-1][j-1])+a[i][j];//动态规划max=res[n-1][0];for(j=1;j<n;j++)if(res[n-1][j]>max) max=res[n-1][j];cout<<max<<endl;cin>>n;}return 0;}例5(poj1157):固定标号顺序的插花问题。
代码:#include<iostream>using namespace std;int a[101][101];int res[101][101];//res[i][j]表示前i朵花放在前j个花瓶中所产生的最大价值int max(int a,int b){return a>b?a:b;}int main(){int i,j,f,v;cin>>f>>v;for(i=1;i<=f;i++)for(j=1;j<=v;j++)cin>>a[i][j];res[1][1]=a[1][1];//求解边界情况for(j=2;j<=v;j++){res[1][j]=res[1][j-1];if(a[1][j]>res[1][j]) res[1][j]=a[1][j];//求解一朵花的情况res[j][j]=res[j-1][j-1]+a[j][j];//求解j个花瓶j朵花的情况}for(i=2;i<=f;i++)//求解其他情况f or(j=i+1;j<=v;j++)res[i][j]=max(res[i][j-1],res[i-1][j-1]+a[i][j]);//动态规划cout<<res[f][v]<<endl;return 0;}例6(poj1125):实际上就是利用Floyd算法求任意顶点对之间的最短路径,只不过要做一下变形而已。
代码:#include<iostream>using namespace std;const int INFINITY=1000000;int a[101][101];//Floyd算法均用邻接矩阵表示图int main(){int i,j,k,n,m,imin,min,max[101];cin>>n;while(n){for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(i==j) a[i][j]=0;else a[i][j]=INFINITY;//初始化for(i=1;i<=n;i++){cin>>m;for(j=1;j<=m;j++)cin>>k,cin>>a[i][k];//输入数据}for(k=1;k<=n;k++)//Floyd算法动态规划for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(a[i][k]+a[k][j]<a[i][j]) a[i][j]=a[i][k]+a[k][j];for(i=1;i<=n;i++)for(j=1;j<=n;j++)if(a[i][j]>max[i])max[i]=a[i][j];//求从i出发到其他顶点的最短距离的最大值min=INFINITY;for(i=1;i<=n;i++)if(max[i]<min) imin=i,min=max[i];//在各顶点中求最小值if(min>=INFINITY) cout<<"disjoint"<<endl;else cout<<imin<<' '<<min<<endl;cin>>n;}return 0;}例7(poj1178):在国王与骑士汇合的所有路径中,求最短路径的长度。
(先将数组降维预处理,再用Floyd动态规划法求解)#include<iostream>#include<string>using namespace std;const int INFINITY=10000;int a[8][2]={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};//王的8种走法int b[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};//马的8种走法int king[64][64];//king[i][j]表示王从位置i到j的最少步数int knight[64][64];//knight[i][j]表示马从位置i到j的最少步数int min(int a,int b){return a<b?a:b;}void init(){int i,j,k;for(i=0;i<64;i++){//初始化for(j=0;j<64;j++)if(i==j) king[i][j]=knight[i][j]=0;else king[i][j]=knight[i][j]=INFINITY;}for(i=0;i<8;i++)//降维的预处理for(j=0;j<8;j++)for(k=0;k<8;k++){if(i+a[k][0]>=0&&i+a[k][0]<=7&&j+a[k][1]>=0&&j+a[k][1]<=7)king[i*8+j][(i+a[k][0])*8+(j+a[k][1])]=1;if(i+b[k][0]>=0&&i+b[k][0]<=7&&j+b[k][1]>=0&&j+b[k][1]<=7)knight[i*8+j][(i+b[k][0])*8+(j+b[k][1])]=1;}}void dp(){int i,j,v;for(v=0;v<64;v++)for(i=0;i<64;i++)for(j=0;j<64;j++){if(king[i][v]+king[v][j]<king[i][j]) king[i][j]=king[i][v]+king[v][j];if(knight[i][v]+knight[v][j]<knight[i][j])knight[i][j]=knight[i][v]+knight[v][j];}}int main(){int i,j,k,sum,res=INFINITY,temp1,temp2;int knight_num,king_pos,knight_pos[63];string str;cin>>str;init();//预处理dp();//Floyd动态规划法knight_num=str.length()/2-1;//马的数量if(knight_num==0) cout<<'0'<<endl,exit(1);king_pos=(str[0]-'A')*8+(str[1]-'1');//王的位置for(i=0;i<knight_num;i++) knight_pos[i]=(str[2*i+2]-'A')*8+(str[2*i+3]-'1');//马的位置for(i=0;i<64;i++){//最终汇合到位置isum=0;for(j=0;j<knight_num;j++) sum+=knight[knight_pos[j]][i];//马走的总步数for(j=0;j<64;j++){//王走到位置j与马汇合temp1=king[king_pos][j];//加上王走的步数temp2=INFINITY;for(k=0;k<knight_num;k++)temp2=min(temp2,knight[knight_pos[k]][j]+knight[j][i]-knight[knight_pos[k]][i]);//特殊处理运载王的马res=min(res,sum+temp1+temp2);}}cout<<res<<endl;return 0;}【小结】关于动态规划的问题,分为两大类:(1)最优子结构——递推求解:分析问题,将其分解为若干个子问题,确定子问题的状态及其状态转移方程,利用子问题的解求原问题的解;(2)重叠子问题——递归求解(记忆化搜索):避免重复求解子问题的一种优化方法。