0x06算法设计与分析复习(二):算法设计策略-贪心法4
参考书籍:算法设计与分析——C++语言描述(第二版)
算法设计策略-贪心法
单源最短路径
问题描述
单源最短路径问题是:给定带权的有向图
贪心法求解
从源点到另一个结点的任意一条路径均可看成是问题的可行解,其中长度最小的路径就是所求的最优解,路径的长度是问题的目标函数。从源点到其余每个结点的最短路径构成了单源最短路径问题的最优解。因此问题解的形式可以认为是:
迪杰斯特拉(Dijkstra)提出了按路径长度的非递减次序逐一产生最短路径的算法:首先求得长度最短的一条最短路径,再求得长度次短的一条最短路径,其余类推,直到从源点到其他所有结点之间的最短路径都已被求出为止。
设
迪杰斯特拉(Dijkstra)算法
设集合S存放已经求得最短路径的终点,则
在算法执行中,一个结点
迪杰斯特拉算法用到以下数据结构:
- 一维数组d[i]中存放从源点s到结点i的当前最短路径的长度。
- 一位整型数组path[i]存放从源点s到结点i的当前最短路径上,结点i的前一个结点。因此,从源点到结点i的路径可以根据path的反向溯源来创建。
- 一维布尔数组inS,若inS[i]为true,表示结点i在S中;否则,表示i不在
V−S 中。
迪杰斯特拉算法计算过程
+ 求第一条最短路径
在初始状态下,集合S中只有一个源点s,
式中,
第一条最短路径是所有最短路径中的最短者,它必须只包含一条边
更新d和path
将结点k加入到S中,并对所有的
i∈V−S 按式d[k]=min{d[i]|i∈V−{s}} 修正,即
d[j]=min{d[j],d[k]+w(k,j)}
式中,w(k,j) 是边<k,j> 的权值。求下一条最短路径
在
V−S 中,选择具有最短的当前最短路径值的结点k,满足d[k]=min{d[i]|i∈V−S} 。
算法的主要步骤如下(有向图用邻接矩阵表示):
- 初始化:创建长度为n的一维数组inS、d和path,并将每个inS[i]初始化为false,d[i]为a[v][i],如果
i≠v 且d[i]<∞ ,则path[i]=v ,否则path[i]=−1 。 - 将源点v加入集合S中:
inS[v]=true;d[v]=0 。 - 使用for循环,按长度的非递减次序,依次产生n-1条最短路径:选出最小的d[k];将结点k加入集合S中,
inS[k]=true ;使用内层for语句更新数组d和path的值,使得其始终代表当前最短路径。
//迪杰斯特拉算法
template<class T>
class MGraph
{
public:
MGraph(int mSize);
void Dijkstra(int s,T*& d, int*& path);
...
private:
int Choose(int *d,boo* s);//在一维数组d中求最小值
...
T** a;//生成二维数组a,存储图的邻接矩阵
int n;//图中顶点数
};
template<class T>
int MGraph<T>::Choose(int *d,bool *s)
{
int i,minpos;
T min;
min=INFTY;
minpos=-1;
for(i=1;i<n;i++)
if(d[i]<min && !s[i]){
min=d[i];
minpos=i;
}
return minpos;
}
template<class T>
void MGraph<T>::Dijkstra(int s,T*& d,int*& path)
{
int k,i,j;
if(s<0 || s>n-1)
throw OutofBound;
bool *inS=new bool[n];
d=new T[n];
path=new int[n];
//初始化
for(i=0;i<n;i++){
inS[i]=false;
d[i]=a[s][i];//a是有向图的邻接矩阵
if(i!=s && d[i]<INFTY)
path[i]=s;
else
path[i]=-1;
}
//将源点加入到S中
inS[s]=true;
d[s]=0;
for(i=1;i<n-1;i++){
//求n-1条最短路径
k=Choose(d,inS);//选出下一条最短路径的结点k
inS[k]=true;//将k加入到S中
for(j=0;j<n;j++){
//更新d和path的值
if(!inS[j] && d[k]+a[k][j]<d[j]){
d[j]=d[k]+a[k][j];
path[j]=k;
}
}
}
}
上述迪杰斯特拉算法的时间复杂度为
算法正确性
设
定理:已知带权有向图
定理:已知带权有向图
定理:已知带非负权值的有向图
定理:已知带非负权值的有向图
磁带最优存储
单带最优存储
问题描述
设有n个程序编号分别为
是求这n个程序的一种排列,使得MRT有最小值。这也等价于求使
贪心法求解
最优量度标准:计算迄今为止已选的那部分程序的D值,选择下一个程序的标准应使得该值的增加最小。
定理:设有n个程序
多带最优存储
问题描述
设有
多带最优存储问题是求n个程序在m条磁带上的一种存储方式,使得
贪心法求解
在多带情况下计算最优平均检索时间,可以先将程序按照长度的非减次序排列,即
//多带最优存储
#include <iostream.h>
void Store(int n, int m)
{
int j=0;
for(int i=0;i<n;i++){
cout<<"将程序"<<i<<"加到磁带"<<j<<endl;
j=(j+1)%m;
}
cout<<endl;
}
定理:设有n个程序