Dijkstra 算法小结 

By Wine93 2013.11

1. Dijkstra 算法相关介绍

算法阐述:Dijkstra是解决单源最短路径的算法,它可以在O(n^2)内计算出源点(s)到图中任何顶点的最短路,但是该算法不能处理存在负权边的图(证明中会给出)。

Dijkstra一般有2种实现,一种采用邻接矩阵,复杂度为O(n^2),这种实现适用于稠密图 (边多点少),还有一种是采用临接表+heap(可用优先队列代替)实现,实现的复杂度为( m*log(n) )   (m为边数,n为顶点数),该实现适用于稀疏图(边少点多),各有各的优缺,视实际情况选择.

 算法简单证明:Dijkstra有2张表(OPEN,CLOSE),我们可以认为一个表存储已经已经计算出最短路径的顶点(假设U),而另一个则存储没有计算出最短路径的顶点(假设V)。Dijkstra每次都取出具有最短路径的顶点(假设NOW),视其就是该顶点的最短路.因为在当前U表中全部扩展的顶点中,NOW顶点是路径最短的顶点,也就是说,其他当前全部可以到达的顶点中,只有大于或等于NOW顶点,如果 通过这些顶点再到达NOW顶点,势必会比现在NOW顶点的路径长,因为原来就大于等于NOW顶点了, 所以NOW顶点路径长度就是源点到该顶点的最短路径.但是如果存在负权边,则会出现通过其他顶点到达NOW顶点的路径长度小于当前NOW顶点的路径长度,这就是为什么Dijkstra不能处理负权边了(请读者看下面例图,模拟下Dijkstra的执行过程)

2.Dijkstra的相关应用举例

一.基础题 

POJ 1511 Invitation Cards

# include<cstdio>
# include<cstring>
# include<algorithm>
# include<queue>
# include<map>
# include<vector>
# include<utility>
using namespace std; # define LL long long
const LL inf=1LL<<;
const int maxn=;
const int maxm=;
typedef pair<int,LL> node; struct edge
{
int u,v,next;
LL w;
} e[maxm]; struct cmp
{
bool operator()(const node &a,const node &b)const
{
return a.second>b.second;
}
}; int num,head[maxn];
LL dis[maxn];
int n,m;
bool vis[maxn];
priority_queue<node,vector<node>,cmp> q; inline void addedge(int u,int v,LL w)
{
e[num].u=u;
e[num].v=v;
e[num].w=w;
e[num].next=head[u];
head[u]=num++;
} void dijkstra(int s)
{
int i,u,v;
for(int i=;i<=n;i++)
{
dis[i]=inf;
vis[i]=;
}
dis[s]=;
q.push(make_pair(s,dis[s]));
while(!q.empty())
{
u=q.top().first;
q.pop();
if(vis[u])
continue;
vis[u]=;
for(i=head[u];i!=-;i=e[i].next)
{
v=e[i].v;
if(!vis[v]&&dis[u]+e[i].w<dis[v])
{
dis[v]=dis[u]+e[i].w;
q.push(make_pair(v,dis[v]));
}
}
}
} void init()
{
num=;
memset(head,-,sizeof(head));
} int main()
{
//freopen("in.txt","r",stdin);
vector<edge> vec;
int T,u,v,i;
LL w;
LL ans;
scanf("%d",&T);
while(T--)
{
ans=;
vec.clear();
init();
scanf("%d%d",&n,&m);
for(i=;i<=m;i++)
{
scanf("%d%d%I64d",&u,&v,&w);
addedge(u,v,w);
}
dijkstra();
for(i=;i<=n;i++)
ans+=dis[i];
for(i=;i<num;i++)
vec.push_back(e[i]);
init();
for(i=;i<vec.size();i++)
addedge(vec[i].v,vec[i].u,vec[i].w);
dijkstra();
for(i=;i<=n;i++)
ans+=dis[i];
printf("%I64d\n",ans);
}
return ;
}

POJ 1511

POJ 3013 Big Christmas Tre(重点在于思维的转换)

# include<cstdio>
# include<cstring>
# include<map>
# include<vector>
# include<queue>
# include<algorithm>
using namespace std; # define LL long long
typedef pair<LL,int> PII;
# define INF 1LL<<
# define N
# define M int num,head[N];
int vis[N];
LL dis[N];
priority_queue< PII,vector<PII>,greater<PII> >q; struct edge
{
int u,v,next;
LL w;
}e[M]; void addedge(int u,int v,LL w)
{
e[num].u=u;
e[num].v=v;
e[num].w=w;
e[num].next=head[u];
head[u]=num++;
} void dijkstra(int n,int s)
{
int i,u,v;
for(i=;i<=n;i++)
{
dis[i]=INF;
vis[i]=;
}
while(!q.empty()) q.pop();
dis[s]=;
q.push(PII(dis[s],s));
while(!q.empty())
{
u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=;
for(i=head[u];i!=-;i=e[i].next)
{
v=e[i].v;
if(!vis[v]&&dis[u]+e[i].w<dis[v])
{
dis[v]=dis[u]+e[i].w;
q.push(PII(dis[v],v));
}
}
}
} void init()
{
num=;
memset(head,-,sizeof(head));
} int main()
{
//freopen("in.txt","r",stdin);
int T,i,n,m,u,v,flag;
LL w,ans,pri[N];
scanf("%d",&T);
while(T--)
{
flag=;
ans=;
init();
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
scanf("%I64d",&pri[i]);
for(i=;i<=m;i++)
{
scanf("%d%d%I64d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
dijkstra(n,);
for(i=;i<=n;i++)
if(dis[i]==INF)
{
flag=;
break;
}
if(!flag) printf("No Answer\n");
else
{
for(i=;i<=n;i++)
ans+=pri[i]*dis[i];
printf("%I64d\n",ans);
}
}
return ;
}

POJ 3013

二.变形题 

POJ 1797 Heavy Transportation

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N
# define M int num,head[N];
int n,m;
int vis[N]; struct edge
{
int u,v,w,next;
}e[M]; void addedge(int u,int v,int w)
{
e[num].u=u;
e[num].v=v;
e[num].w=w;
e[num].next=head[u];
head[u]=num++;
} int dfs(int u,int limit)
{
int i,v;
vis[u]=;
if(u==n)
return ;
for(i=head[u];i!=-;i=e[i].next)
{
v=e[i].v;
if(!vis[v]&&e[i].w>=limit)
{
if(dfs(v,limit))
return ;
}
}
return ;
} int pass(int limit)
{
memset(vis,,sizeof(vis));
if(dfs(,limit))
return ;
return ;
} int bin(int l,int r)
{
int m;
while(l<=r)
{
m=(l+r)>>;
if(pass(m))
l=m+;
else
r=m-;
}
return r;
} void init()
{
num=;
memset(head,-,sizeof(head));
} int main()
{
// freopen("in.txt","r",stdin);
int cas,T,i,u,v,w;
scanf("%d",&T);
for(cas=;cas<=T;cas++)
{
init();
scanf("%d%d",&n,&m);
for(i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
printf("Scenario #%d:\n",cas);
printf("%d\n\n",bin(,));
}
return ;
}

POJ 1797 二分

# include<cstdio>
# include<cstring>
# include<map>
# include<queue>
# include<vector>
# include<algorithm>
using namespace std; typedef pair<int,int> PII;
# define N
# define M
priority_queue< PII,vector<PII>,less<PII> > q; //pair<dis,u> dis从大到小 int num,head[N];
int dis[N]; struct edge
{
int u,v,w,next;
}e[M]; void addedge(int u,int v,int w)
{
e[num].u=u;
e[num].v=v;
e[num].w=w;
e[num].next=head[u];
head[u]=num++;
} void dijkstra(int n,int s)
{
int i,u,v;
for(i=;i<=n;i++)
dis[i]=;
dis[s]=<<;
q.push(PII(dis[s],s));
while(!q.empty())
{
PII now=q.top();
u=now.second;
q.pop();
if(now.first<dis[u]) continue;
for(i=head[u];i!=-;i=e[i].next)
{
v=e[i].v;
if(dis[v]<min(dis[u],e[i].w))
{
dis[v]=min(dis[u],e[i].w);
q.push(PII(dis[v],v));
}
}
}
} void init()
{
num=;
memset(head,-,sizeof(head));
} int main()
{
//freopen("in.txt","r",stdin);
int cas,T,i,n,m,u,v,w;
scanf("%d",&T);
for(cas=;cas<=T;cas++)
{
init();
scanf("%d%d",&n,&m);
for(i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
}
dijkstra(n,);
printf("Scenario #%d:\n",cas);
printf("%d\n\n",dis[n]);
}
return ;
}

POJ 1797 Dijkstra

POJ 2253 Frogger

# include<cstdio>
# include<cstring>
# include<cmath>
# include<map>
# include<queue>
# include<vector>
# include<algorithm>
using namespace std; # define INF <<
# define N int vis[N];
double dis[N];
double mat[N][N]; struct point
{
double x,y;
}p[N]; double calc(point a,point b)
{
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
} void dijkstra(int n,int s)
{
double mind;
int i,j,u,v;
dis[s]=;
for(i=;i<=n;i++)
{
mind=<<;
for(j=;j<=n;j++)
if(!vis[j]&&dis[j]<mind)
{
mind=dis[j];
u=j;
}
vis[u]=;
for(v=;v<=n;v++)
if(!vis[v]&&dis[v]>max(dis[u],mat[u][v]))
dis[v]=max(dis[u],mat[u][v]);
}
} void init(int n)
{
int i,j;
for(i=;i<=n;i++)
{
vis[i]=;
dis[i]=INF;
for(j=;j<=n;j++)
mat[i][j]=INF;
}
} int main()
{
// freopen("in.txt","r",stdin);
int i,j,n,cas=;
while(scanf("%d",&n)!=EOF&&n)
{
init(n);
for(i=;i<=n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
for(i=;i<=n;i++)
for(j=i+;j<=n;j++)
mat[i][j]=mat[j][i]=calc(p[i],p[j]);
dijkstra(n,);
printf("Scenario #%d\n",cas++);
printf("Frog Distance = %.3lf\n\n",dis[]);
}
return ;
}

POJ 2253

将这2题放在一起讲(2题都可用2分解),我们可以利用Dijkstra特殊的结构解决一类问题----单调路径(况且这么叫),所谓单调路径,即为对于任何一条路径, 我们所求的值只会成单调变化

拿POJ1797来说,每经过一条路径,weight的值只会减少(甚至不变),不会增加,看下图(边权值表示 weight,红色顶点为起点,绿色为终点,顶点下数字表示从起始点到达该顶点的weight值)

我们可以发现weight呈现非递增,而我们要求的则是weight的最大值,也就是说我们求的和它的趋势相反都可用Dijkstra来题解(请看下图),这跟Dijkstra可用heap优化是异曲同工(可以认真理解证明)

如果所求值和趋势为同一走向则不能用Dijkstra求解(如最长路)

 三.好题

POJ 3463 Sightseeing

3.个人心得

Dijkstra的变形和应用非常多,需要一定的时间和题量积累,但是只要能深入理解Dijkstra的贪心 策略以及他在单调路径上(况且这么叫)的作用,很多问题都会迎刃而解

[图论]Dijkstra 算法小结的更多相关文章

  1. [图论]Floyd 算法小结

    Floyd 算法小结  By Wine93 2013.11 1. Floyd算法简介 Floyd算法利用动态规划思想可以求出任意2点间的最短路径,时间复杂度为O(n^3),对于稠密图, 效率要高于执行 ...

  2. Cocos2d-x 地图步行实现1:图论Dijkstra算法

    下一节<Cocos2d-x 地图行走的实现2:SPFA算法>: http://blog.csdn.net/stevenkylelee/article/details/38440663 本文 ...

  3. 图论——Dijkstra算法

    图论其实是比较难的一种题型,但是一些模板题,是没有什么太大难度的! 这里给大家带来的是迪杰斯特拉(Dijkstra)算法. 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄 ...

  4. 图论--Dijkstra算法总结

    Key word: ①BFS转换Dijkstra ②其他关系转化为最短路 ③反向建边及反向Dijkstra ④稠密图.稀疏图 ⑤链式前向星 ⑥Vector建图 ⑦超级源点&汇点 详解: 1.B ...

  5. 《算法导论》读书笔记之图论算法—Dijkstra 算法求最短路径

    自从打ACM以来也算是用Dijkstra算法来求最短路径了好久,现在就写一篇博客来介绍一下这个算法吧 :) Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的 ...

  6. 图论基础之Dijkstra算法的初探

         图论,顾名思义就是有图有论.        图:由点"Vertex"和边"Edge "组成,且图分为有向图和无向图(本文讨论有向图),之前做毕业设计的 ...

  7. 图论之Dijkstra算法

    Dijkstra算法是图论中经典的最短路径算法之一,主要用于解决单源最短路径问题. 单源最短路径问题,即求某个源节点到其他各个节点的最短路径. Dijkstra算法采用了贪心算法的思想,如图求1号节点 ...

  8. 图论之最短路径(1)——Floyd Warshall & Dijkstra算法

    开始图论学习的第二部分:最短路径. 由于知识储备还不充足,暂时不使用邻接表的方法来计算. 最短路径主要分为两部分:多源最短路径和单源最短路径问题 多源最短路径: 介绍最简单的Floyd Warshal ...

  9. 数据结构实验之图论七:驴友计划 ( 最短路径 Dijkstra 算法 )

    数据结构实验之图论七:驴友计划 Time Limit: 1000 ms           Memory Limit: 65536 KiB Submit Statistic Discuss Probl ...

随机推荐

  1. ACTIVITI 研究代码 之 模版模式

    模板方法模式需要开发抽象类和具体子类的设计师之间的协作.一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤.代表这些具体逻辑步骤的方法称做基本方法(primitive ...

  2. Window["aaa"]这个在JS里是什么意思?

    答案:定义一个全局的变量 aaa,这个的方式是数组,实际上是等于 window.aaa

  3. MongoDb系列

    这个系列主要总结学习MongoDb过程中的一些经验. 简单介绍及环境搭建 常用命令 C#驱动及应用 管理工具MongoVUE使用

  4. @property和@synthesize的特性

    基础回顾:get方法和set方法 定义类成员变量时,可以在@interface中定义,也可以在@implementation中定义: 在@interface中声明,成员变量的状态是受保护的,即“@pr ...

  5. Android webview 取得javascript返回值

    package com.she.jyass.UI; import android.content.Context; import android.webkit.WebView; public clas ...

  6. HDU 3265 扫描线(矩形面积并变形)

    Posters Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Sub ...

  7. ActiveX 技术疑点 一

    1.编写基于MFC Activex 使用 静态库 .lib , MFC 的使用 在静态库中使用MFC . 生成ocx 文件 注册失败.提示: ***还是一个可执行文件,没有为这个文件类型注册的注册帮助 ...

  8. STL-算法

    #include <algorithm> 1. max_element(v.begin(), v.end()); 注意,所有的区间全部是半开区间,如果数组包含20-40,通过find找出2 ...

  9. Spring依赖关系

    在Spring中,各个模块的依赖关系通过简单的IoC配置文件进行描述,使这些外部化的信息集中并且明了,我们在使用其他组件服务时,只需要去配置文件中了解和配置这些依赖关系即可,也就是说这里关心的是接口, ...

  10. Spring学习笔记之初始化和销毁方法的调用次序

    Multiple lifecycle mechanisms configured for the same bean, with different initialization methods, a ...