[图论]Dijkstra 算法小结
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 算法小结的更多相关文章
- [图论]Floyd 算法小结
Floyd 算法小结 By Wine93 2013.11 1. Floyd算法简介 Floyd算法利用动态规划思想可以求出任意2点间的最短路径,时间复杂度为O(n^3),对于稠密图, 效率要高于执行 ...
- Cocos2d-x 地图步行实现1:图论Dijkstra算法
下一节<Cocos2d-x 地图行走的实现2:SPFA算法>: http://blog.csdn.net/stevenkylelee/article/details/38440663 本文 ...
- 图论——Dijkstra算法
图论其实是比较难的一种题型,但是一些模板题,是没有什么太大难度的! 这里给大家带来的是迪杰斯特拉(Dijkstra)算法. 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄 ...
- 图论--Dijkstra算法总结
Key word: ①BFS转换Dijkstra ②其他关系转化为最短路 ③反向建边及反向Dijkstra ④稠密图.稀疏图 ⑤链式前向星 ⑥Vector建图 ⑦超级源点&汇点 详解: 1.B ...
- 《算法导论》读书笔记之图论算法—Dijkstra 算法求最短路径
自从打ACM以来也算是用Dijkstra算法来求最短路径了好久,现在就写一篇博客来介绍一下这个算法吧 :) Dijkstra(迪杰斯特拉)算法是典型的最短路径路由算法,用于计算一个节点到其他所有节点的 ...
- 图论基础之Dijkstra算法的初探
图论,顾名思义就是有图有论. 图:由点"Vertex"和边"Edge "组成,且图分为有向图和无向图(本文讨论有向图),之前做毕业设计的 ...
- 图论之Dijkstra算法
Dijkstra算法是图论中经典的最短路径算法之一,主要用于解决单源最短路径问题. 单源最短路径问题,即求某个源节点到其他各个节点的最短路径. Dijkstra算法采用了贪心算法的思想,如图求1号节点 ...
- 图论之最短路径(1)——Floyd Warshall & Dijkstra算法
开始图论学习的第二部分:最短路径. 由于知识储备还不充足,暂时不使用邻接表的方法来计算. 最短路径主要分为两部分:多源最短路径和单源最短路径问题 多源最短路径: 介绍最简单的Floyd Warshal ...
- 数据结构实验之图论七:驴友计划 ( 最短路径 Dijkstra 算法 )
数据结构实验之图论七:驴友计划 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Probl ...
随机推荐
- 教你如何做好SEO优化中的前端优化
网站的速度是很多人都面临的问题,其实许多网站,都没有特意的去优化加载速度,对于一个网站来说,加速不但提高了用户体验(如果一个网站在几秒内没 有打开,大多数用户选择的是关闭而非等待),而且对于SEO的流 ...
- jQuery性能优化指南(转载)
现在jquery应用的越来越多, 有些同学在享受爽快淋漓coding时就将性能问题忽略了, 比如我. jquery虽在诸多的js类库中性能表现还算优秀, 但毕竟不是在用原生的javascript开发, ...
- [原创]Keys的基本操作总结,判断Keys中是否存在Keys.Control|Keys.Alt,移除Keys中的部分键值。
直接看应用实例 /// <summary> /// 组合键转换成字符串类型 /// </summary> /// <param name="keyCode&qu ...
- input 中的enabled与disabled属性
<style type="text/css"> *{ padding:; margin:; list-style-type: none; box-sizing:bord ...
- linux bash: sqlplus: command not found 错误处理
在oracle用户下 ,执行sqlplus命令,抛出如上错误. 解决办法: 1.su oracle 2.cd /home/oracle 3. 执行命令 source .bash_pro ...
- changepassword.c 0.9:一个通过WEB界面更改LINUX用户密码的程序
偶然看到一个用C语言写的CGI程序,可以以WEB界面(无需单独再写HTML)的方式修改用户自己的密码.该程序具有同时修改samba及squid密码的能力. 步骤: 1.下载并解压,并读一下README ...
- 使用MediaPlayer播放音频-----之二
MediaPlayer播放不同来源的音频文件: 一.播放应用的资源文件 1.调用MediaPlayer的create(Context context , int resid)方法加载指定资源文件. ...
- if语句使用
package yuan; public class Yuan { public static void main(String[] args) { int a = 1; int b = 8; int ...
- 2014北邮新生归来赛解题报告a-c
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...
- 使用ASP.Net WebAPI构建REST服务(二)——路由
REST并没有像传统的RPC服务那样显式指定了服务器函数的访问路径,而是将URL根据一定的规则映射为服务函数入口,这个规则就称之为路由.Asp.Net WebAPI的路由方式和Asp.Net MVC是 ...