关于dijkstra的一点总结
2013-07-19 17:07
148 查看
最近的一段时间都在刷关于dijkstra的东西 ,在参看了白书等参考之后 ,我个人做了点小总结。首先要明确的是dijkstra的最主要用途是求单源最短路径的(权值非负)。所谓单源最短路径就是固定一个顶点为源点,然后求源点到其他点的最短路径。(需要特别注意的是 源点不一定是图中标明的起点,有时候出题者经常会反着来,这时候就需要用反的dijkstra来做,即将终点当源点向多个起点来辐射)
算法的思想:从顶点v0到vk的最短路径,要么是从v0到vk的直接路径,要么就是从v0经过某个顶点vi再到vk的路径。
具体实现方法:
1、设置两个顶点的集合T和S S中存放已经找到的最短路径的点,初始时只有一个顶点,既源点v0。T中存放的是还未找到最短路径的点。
2、在T中选取当前长度最短的一条路径(v0……vk),从而将vk加入S中,并修改源点v0到T中各个顶点的最短路径长度;重复这一步骤,直到所有的顶点都加入S中,算法结束。
算法实现:
一般有几个常用的数组。
dist[i]:表示当前找到的从源点v0出发到vi的最短路径的长度。初始 时,dist[i]为edge[vo][i],既邻接矩阵的第v0行。
s
:s[i]为0表示顶点vi还未加入集合s中,为1表示已加入。初始时,s[v0]为1,其他的都为0.
path
:path[ i ]表示v0到vi的最短路径上顶点vi的前一个顶点序号。用来记录最短路径的。
递推公式:
初始: dist[k]=edge[v0][k],v0是源点
递推:u=min{dist[i]},vt∈T
u 表示当前T集合中dist数组的元素最小的顶点的序号,此后u加入集合s中。
dist[k]=min{dist[u]+edge[u][k]},vk∈T(只修改T中顶点的dist值)
下面是代码模板:
memset(s,false,sizeof(s));
for(i=0;i<n-1;i++){
int min=inf,u=v0;
for(j=0;j<n;j++){
if(!s[j]&&dist[j]<min){
u=j;
min=dist[j];
}
}
s[u]=true;
for(k=0;k<n;k++){
if(!s[k]&&edge[u][k]<inf&&dist[u]+edge[u][k]<dist[k]){
dist[k]=dist[u]+edge[u][k];
path[k]=u;
}
}
}
当然上面的算法并不是最好的,如果面对数据过大的时候,这个dijkstra就用不了,所以必须用优先队列改进的dijkstra。关于这一点我不是太清楚 ,只能照着白书 的模板敲了。
下面是代码:
struct cmp{
bool operator() (const int a,const int b){
return a>b;
}
};
priority_queue<int,vector<int>,cmp> q;
bool done[maxn];
for(int i=0;i<n;i++)
d[i]=(i==0?0:inf);
memset(done,0,sizeof(done));
q.push(make_pair(d[0],0));
while(!q.empty()){
pii u=q.top();
q.pop();
int x=u.second;
if(done[x]) continue;
done[x]=true;
for(int e=first[x];e!=-1;e=next[e])
if(d[v[e]]>d[x]+w[e]){
d[v[e]]=d[x]+w[e];
q.push(make_pair(d[v[e]],v[e]));
}
}
算法的思想:从顶点v0到vk的最短路径,要么是从v0到vk的直接路径,要么就是从v0经过某个顶点vi再到vk的路径。
具体实现方法:
1、设置两个顶点的集合T和S S中存放已经找到的最短路径的点,初始时只有一个顶点,既源点v0。T中存放的是还未找到最短路径的点。
2、在T中选取当前长度最短的一条路径(v0……vk),从而将vk加入S中,并修改源点v0到T中各个顶点的最短路径长度;重复这一步骤,直到所有的顶点都加入S中,算法结束。
算法实现:
一般有几个常用的数组。
dist[i]:表示当前找到的从源点v0出发到vi的最短路径的长度。初始 时,dist[i]为edge[vo][i],既邻接矩阵的第v0行。
s
:s[i]为0表示顶点vi还未加入集合s中,为1表示已加入。初始时,s[v0]为1,其他的都为0.
path
:path[ i ]表示v0到vi的最短路径上顶点vi的前一个顶点序号。用来记录最短路径的。
递推公式:
初始: dist[k]=edge[v0][k],v0是源点
递推:u=min{dist[i]},vt∈T
u 表示当前T集合中dist数组的元素最小的顶点的序号,此后u加入集合s中。
dist[k]=min{dist[u]+edge[u][k]},vk∈T(只修改T中顶点的dist值)
下面是代码模板:
memset(s,false,sizeof(s));
for(i=0;i<n-1;i++){
int min=inf,u=v0;
for(j=0;j<n;j++){
if(!s[j]&&dist[j]<min){
u=j;
min=dist[j];
}
}
s[u]=true;
for(k=0;k<n;k++){
if(!s[k]&&edge[u][k]<inf&&dist[u]+edge[u][k]<dist[k]){
dist[k]=dist[u]+edge[u][k];
path[k]=u;
}
}
}
当然上面的算法并不是最好的,如果面对数据过大的时候,这个dijkstra就用不了,所以必须用优先队列改进的dijkstra。关于这一点我不是太清楚 ,只能照着白书 的模板敲了。
下面是代码:
struct cmp{
bool operator() (const int a,const int b){
return a>b;
}
};
priority_queue<int,vector<int>,cmp> q;
bool done[maxn];
for(int i=0;i<n;i++)
d[i]=(i==0?0:inf);
memset(done,0,sizeof(done));
q.push(make_pair(d[0],0));
while(!q.empty()){
pii u=q.top();
q.pop();
int x=u.second;
if(done[x]) continue;
done[x]=true;
for(int e=first[x];e!=-1;e=next[e])
if(d[v[e]]>d[x]+w[e]){
d[v[e]]=d[x]+w[e];
q.push(make_pair(d[v[e]],v[e]));
}
}
相关文章推荐
- 关于DNN Module开发学习以来的一点总结
- 关于先序中序后序遍历二叉树的一点总结
- 关于在SetWindowLong函数中使用cbWndExtra的一点总结
- 关于工作的一点总结和思考
- 关于java的环境变量的一点总结
- [置顶] 关于ora-1652的一点总结–续(详解rowid,index entry header)
- 关于的无穷级数的一点总结
- 关于c++内存的一点总结20150603
- 在JZ2440板上关于一直Boa服务器的一点心得总结
- 关于窗体(Windows Form)的CreateParams(属性或参数)的一点总结!
- 菜鸟编程 关于函数的一点总结
- 关于java内存的一点总结
- 关于switch的LED指示灯的一点总结
- 关于单元测试中STUB的一点总结
- 关于测试的一点总结
- 关于CPU位数,OS位数以及内存大小关系的一点总结
- 关于Static的一点总结
- 关于DataGridView,ComboBox,XDocument和XElement的一点总结
- jquery关于val,attr的一点总结
- 关于ora-1652的一点总结–续(详解rowid,index entry header)