动态规划系列之一 引言 :由一个问题引出的算法
2012-12-04 14:52
316 查看
http://iprai.hust.edu.cn/icl2002/algorithm/algorithm/technique/dynamic_programming/introduction.htm
[例1] 最短路径问题
现有一张地图,各结点代表城市,两结点间连线代表道路,线上数字表示城市间的距离。如图1所示,试找出从结点A到结点E的最短距离。
图 1
我们可以用深度优先搜索法来解决此问题,该问题的递归式为
其中
是与v相邻的节点的集合,w(v,u)表示从v到u的边的长度。
具体算法如下:
开始时标记所有的顶点未访问过,MinDistance(A)就是从A到E的最短距离。
这个程序的效率如何呢?我们可以看到,每次除了已经访问过的城市外,其他城市都要访问,所以时间复杂度为O(n!),这是一个“指数级”的算法,那么,还有没有更好的算法呢?
首先,我们来观察一下这个算法。在求从B1到E的最短距离的时候,先求出从C2到E的最短距离;而在求从B2到E的最短距离的时候,又求了一遍从C2到E的最短距离。也就是说,从C2到E的最短距离我们求了两遍。同样可以发现,在求从C1、C2到E的最短距离的过程中,从D1到E的最短距离也被求了两遍。而在整个程序中,从D1到E的最短距离被求了四遍。如果在求解的过程中,同时将求得的最短距离"记录在案",随时调用,就可以避免这种情况。于是,可以改进该算法,将每次求出的从v到E的最短距离记录下来,在算法中递归地求MinDistance(v)时先检查以前是否已经求过了MinDistance(v),如果求过了则不用重新求一遍,只要查找以前的记录就可以了。这样,由于所有的点有n个,因此不同的状态数目有n个,该算法的数量级为O(n)。
更进一步,可以将这种递归改为递推,这样可以减少递归调用的开销。
请看图1,可以发现,A只和Bi相邻,Bi只和Ci相邻,...,依此类推。这样,我们可以将原问题的解决过程划分为4个阶段,设S1={A},S2={B1,B2},S3={C1,C2,C3,C4},S4={D1,D2,D3},Fk(u)表示从Sk中的点u到E的最短距离,则
并且有边界条件
显然可以递推地求出F1(A),也就是从A到E的最短距离。这种算法的复杂度为O(n),因为所有的状态总数(节点总数)为n,对每个状态都只要遍历一次,而且程序很简洁。
具体算法如下:
这种高效算法,就是动态规划算法。
以下是上述两个算法的具体实现
引言——由一个问题引出的算法
考虑以下问题[例1] 最短路径问题
现有一张地图,各结点代表城市,两结点间连线代表道路,线上数字表示城市间的距离。如图1所示,试找出从结点A到结点E的最短距离。
图 1
我们可以用深度优先搜索法来解决此问题,该问题的递归式为
其中
是与v相邻的节点的集合,w(v,u)表示从v到u的边的长度。
具体算法如下:
function MinDistance(v):integer; begin if v=E then return 0 else begin min:=maxint; for 所有没有访问过的节点i do if v和i相邻 then begin 标记i访问过了; t:=v到i的距离+MinDistance(i); 标记i未访问过; if t<min then min=t; end; end; end;
开始时标记所有的顶点未访问过,MinDistance(A)就是从A到E的最短距离。
这个程序的效率如何呢?我们可以看到,每次除了已经访问过的城市外,其他城市都要访问,所以时间复杂度为O(n!),这是一个“指数级”的算法,那么,还有没有更好的算法呢?
首先,我们来观察一下这个算法。在求从B1到E的最短距离的时候,先求出从C2到E的最短距离;而在求从B2到E的最短距离的时候,又求了一遍从C2到E的最短距离。也就是说,从C2到E的最短距离我们求了两遍。同样可以发现,在求从C1、C2到E的最短距离的过程中,从D1到E的最短距离也被求了两遍。而在整个程序中,从D1到E的最短距离被求了四遍。如果在求解的过程中,同时将求得的最短距离"记录在案",随时调用,就可以避免这种情况。于是,可以改进该算法,将每次求出的从v到E的最短距离记录下来,在算法中递归地求MinDistance(v)时先检查以前是否已经求过了MinDistance(v),如果求过了则不用重新求一遍,只要查找以前的记录就可以了。这样,由于所有的点有n个,因此不同的状态数目有n个,该算法的数量级为O(n)。
更进一步,可以将这种递归改为递推,这样可以减少递归调用的开销。
请看图1,可以发现,A只和Bi相邻,Bi只和Ci相邻,...,依此类推。这样,我们可以将原问题的解决过程划分为4个阶段,设S1={A},S2={B1,B2},S3={C1,C2,C3,C4},S4={D1,D2,D3},Fk(u)表示从Sk中的点u到E的最短距离,则
并且有边界条件
显然可以递推地求出F1(A),也就是从A到E的最短距离。这种算法的复杂度为O(n),因为所有的状态总数(节点总数)为n,对每个状态都只要遍历一次,而且程序很简洁。
具体算法如下:
procedure DynamicProgramming; begin F5[E]:=0; for i:=4 downto 1 do for each u ∈Sk do begin Fk[u]:=无穷大; for each v∈Sk+1∩δ(u) do if Fk[u]>w(u,v)+Fk+1[v] then Fk[u]:=w(u,v)+Fk+1[v]; end; 输出F1[A]; end;
这种高效算法,就是动态规划算法。
以下是上述两个算法的具体实现
#include <fstream> ifstream fin("in.txt"); #define maxLength 20 #define maxPath 20 #define MAX 1000000 int matrix[maxLength][maxLength];//有向图临界表 int minPath[maxPath];//存储每个节点到终点的最短路径 int trace[maxLength];//记录下最短路径 int v_n;//节点个数 int visited[maxLength]; int MinDistance_1(int v) { if(v==v_n-1) { return 0; } int min=MAX,t,j; for(int i=v+1;i<=v_n-1;i++)//所有没有访问过的节点i { if(!visited[i]&&matrix[v][i]!=0)//如果没有访问过的节点i { visited[i]=true; t=matrix[v][i]+MinDistance_1(i); visited[i]=false; if(t<min) min=t; } } return min; } int MinDistance(int v) { if(minPath[v]>0)//记忆化搜索 存储的是每个节点到终点的最短路径 return minPath[v]; if(v==v_n-1) return 0;//边界值 int min=1000,t,j; for(int i=v+1;i<v_n;i++) { if(matrix[v][i]>0) { t=matrix[v][i]+MinDistance(i); if(min>t) { min=t; j=i; } } } minPath[v]=min; trace[v]=j;//trace[i]的值为其下一个节点的值 return minPath[v]; } int main() { fin>>v_n; for(int i=0;i<v_n;i++) { for(int j=0;j<v_n;j++) { fin>>matrix[i][j]; cout<<matrix[i][j]<<"-"; } cout<<endl; } memset(visited,0,sizeof(int)*maxLength); memset(minPath,0,sizeof(int)*maxLength); memset(trace,0,sizeof(int)*maxLength); int minD=MinDistance_1(0); cout<<"最短路径为:"<<minD<<endl; return 0; }
相关文章推荐
- 【算法系列-5】动态规划-背包问题
- 计算机算法--动态规划0-1背包问题
- 算法系列-topk问题
- 每天学习一算法系列(4) (输入一个整形数组,数组里有正数也有负数,数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和)
- 【算法设计-动态规划】钢条切割问题
- 每天学习一算法系列(30)(给一个很长的字符串str 还有一个字符集比如{a,b,c} 找出str 里包含{a,b,c}的最短子串。要求O(n).)
- 算法系列之二:三只水桶等分水问题
- 算法系列之十四:狼、羊、菜和农夫过河问题
- 一个取巧找重复值的算法问题
- 一个关于拼图算法的问题
- 【算法学习】切割木棍问题——动态规划
- 一个C笔试题引出一系列的问题
- 一个算法问题的解决
- JAVA代码—算法基础:数塔问题(动态规划)
- 整数划分 --- 一个老生长谈的问题 动态规划
- 常考经典算法---动态规划(拼凑面额、背包问题)
- 一个数独问题的算法(已更新,提供一个简单算法,欢迎拍砖)
- 【算法】可用动态规划求解的问题的基本特征
- 算法java实现--动态规划--0-1背包问题
- 9轴陀螺仪KF系列算法的轴向问题