最短路算法汇总
来源:互联网 发布:mac可以加硬盘吗 编辑:程序博客网 时间:2024/05/18 16:39
校赛完了,这次校赛,做的很差,一个算法题没有,2个水题,1个贪心,概率DP,DP,数论题。DP还没开始研究,数论根本不会,数学太差了,省赛时卡数论,校赛依然卡数论,我擦,还是得继续学习啊!
一把锈迹斑斑的剑,只有不断的磨砺,才能展露锋芒!
以下为最短路总结:
最短路问题可分为:
二、每对顶点间的最短路径算法:Floyd;
(1).Dijkstra算法:
(经典的算法,可以说是最短路问题的首选事例算法,但是不能处理带负权的边,因为该算法要遍历的点过多,效率低下,用时长,仅限于小数据,不常用)
基本思想:
Dijkstra算法,本质上是利用贪心思想来不停的来进行贪心选择,查找最优解,开辟一个s[],用来存放这些点,
dis[]用来存放所能经过的每个点的最短距离,并进行dis[]的更新操作。注意:只能处理无负权的边
模版如下:
int m,n,map[max][max],dis[max],s[max];//int prev[max];//当前点的上一个节点 void Dijkstra(int v0) { for(int i = 0;i<n;i++) //初始化dis[] { s[i] = 0; dis[i] = map[v0][i]; /* if(i!=v0 && map[v0][i]<inf) prev[i] = v0 else prev[i] = -1; */ } s[v0] = 1; dis[v0] = 0; for(int i = 2;i<=n;i++) { int u = v0,min = inf; for(int j = 0;j<n;j++)//贪心查找还未存储的最优解的点,并储存 { if(!s[j] && dis[j] < min)//当前最短距离 { u = j;//记录下标 min = dis[j]; } } s[u] = 1; for(int j = 0;j<n;j++)//更新dis[]数组 { if(!s[j] && map[u][j] < inf && dis[u] + map[u][j] < dis[j]) { dis[j] = map[u][j] + dis[u]; //prev[j] = u; } } } }
优先队列的Dijkstra
HDU 1874
#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>#include <queue>#include <vector>const int N = 10001;const int INF = 1e7;using namespace std;struct node{ int x,d; node(){} node(int a,int b) { x=a; d=b; } bool operator <(const node & a)const { if(d == a.d) return x < a.x ; else return d > a.d; }};vector <node> ma[N];int dis[N],n;void Dijkstra(int s){ for(int i=0;i<=n;i++) dis[i]=INF; dis[s]=0; priority_queue<node> q; q.push(node(s,dis[s])); while(!q.empty()) { node p=q.top(); q.pop(); int s = ma[p.x].size(); for(int i=0;i<s;i++) { node pp=ma[p.x][i]; if(dis[pp.x]>p.d+pp.d) { dis[pp.x]=p.d+pp.d; q.push(node(pp.x,dis[pp.x])); } } }}int main(){ int a,b,c,m,s,e; while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<=n;i++) ma[i].clear(); while(m--) { scanf("%d%d%d",&a,&b,&c); ma[a].push_back(node(b,c)); ma[b].push_back(node(a,c)); } scanf("%d%d",&s,&e); Dijkstra(s); if(dis[e]!=INF) printf("%d\n",dis[e]); else puts("-1"); } return 0;}
// 题意: 有n*m矩阵,从起点(sx,sy)出发,可以上下左右四个方向移动,// 若两个位置上是相同字符,则花费为0,否则为1,求到终点的最短距离// 用Dijkstra算法解决,但会 TLE ,需要用 优先队列 优化时间#include <iostream> // 邻接矩阵+优先队列实现Dijkstra算法#include <stdio.h>#include <queue>#include <cstring>using namespace std; const int INF=300000;const int MAXN=250000;int n,m,distD[MAXN],done[MAXN]; int sx,sy,tx,ty; //起点(sx,sy)和终点(tx,ty)int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};char data[500][500];typedef pair<int,int> pii;void Dijkstra(int st) //从源点st到其余各顶点的最短路径长度{ priority_queue<pii, vector<pii>, greater<pii> > q; fill(distD,distD+n*m,INF); //结点下标从0开始,共有 m * n 个结点 distD[st]=0; fill(done,done+n*m,0); q.push(make_pair(distD[st], st)); while(!q.empty()) { pii u = q.top(); q.pop(); int p = u.second; if(done[p]) continue; done[p] = 1; if( p == tx * m + ty ) // 如果探测到终点即可退出 { printf("%d\n",distD[p]); break; } for(int d=0;d<4;++d) { int newx=p/m+dx[d],newy=p%m+dy[d]; int newp=newx*m+newy; if(newx>=0&&newx<n&&newy>=0&&newy<m&& !done[newp] ) { int w = ( data[p/m][p%m] == data[newx][newy] ) ? 0 : 1 ; if( distD[p] + w < distD[newp] ) { distD[newp]=distD[p]+w; q.push(make_pair(distD[newp], newp)); } } } }}int main(){ while(scanf("%d%d",&n,&m)!=EOF) // n 行 m 列 { for(int i=0;i<n;++i) { scanf("%s",data[i]); } scanf("%d%d%d%d",&sx,&sy,&tx,&ty); Dijkstra(sx*m+sy); // 顶点坐标[x,y],则在队列对应的下标是 x * m + y } return 0;}
(用来判断是否有回环,可处理带负权边 时间复杂度O(V*E).)
基本思想:(DP思想,查找最优解,并不断的进行松弛操作,但是算法浪费了许多时间做冗杂的松弛操作,效率降低) 无向图
void add(){ scanf("%d%d%d",&u,&v,&w); edge[l].u = u; edge[l].v = v; edge[l++].w = w; edge[l].u = v; edge[l].v = u; edge[l++].w = w;}int Bellman(int cnt){ int i,j,flag; for(i = 1;i <= N - 1;i++) { flag = 0; for(j = 0;j <= count - 1;j++) { if(dis[edge[j].u]> dis[edge[j].v] + edge[j].w) { //松弛计算 dis[edge[j].u] = dis[edge[j].v] + edge[j].w;//更新dis[]数组,使其存储 源点->当前点的最短距离 flag = 1; } } if(flag==0)//如果查找完,或者有些点达不到,跳出->优化 break; } for(i = 0;i < count;i++)//判断是否有负环路 { if(dis[edge[i].u] > dis[edge[i].v] + edge[i].w)//更新完dis[]后,如果还存在 该成立条件,则存在负环路 return 1; } // 如1->2 权值2 return 0; // 2->3 权值5 // 3->1 权值-8 // 1->2->3->1 一次循环为-1 二次-2 三次....这就叫负环}
(2)FLOYD
这个实在没什么好说的,做题目时,只要确定的 时间不超,就可以用,前提是记下,时间复杂度O(n*n*n).
ma[u][v] 储存的就是u->v的距离
void init() { for(i=0;i<n;i++) for(j=0;j<n;j++) { map[i][j] = (i==j)?0:inf; } }void floyd(){ for(k=0;k<n;k++) { for(i=0;i<n;i++) { for(j=0;j<n;j++) { if(map[i][k]!=inf && map[k][j]!=inf && map[i][j]>map[i][k] + map[k][j] ) { map[i][j]=map[i][k]+map[k][j]; } } } }}
(4)SPFA
书上说是在bellman-ford的基础上,添加一个队列操作,减少了其不必要的松弛操作。
我个人认为是在BFS搜索的基础上加了一步所谓的松弛操作,至于为什么叫松弛,不懂。
但是SPFA优化的很棒,以后最短路问题,尽量用它。无向图
矩阵式
void SPFA(int s,int e) S点 到e点{ int l,r,i; l=r=0; memset(vt,0,sizeof(vt)); for(i=s;i<e+1;i++) dis[i]=inf; dis[s]=0; q[r++]=s;//进队列 vt[s]=1;//标记 进队列1 //不在队列为0 while(l<r) { int p=q[l++];//出队列 for(i=0;i<n;i++)//枚举与p相连的点 { if(dis[i]>dis[p] + map[p][i])//松弛 { dis[i] = dis[p] + map[p][i]; if(!vt[i]) { q[r++] = i; vt[i] = 1; } } } vt[p] = 0; } if(dis[e]!= inf) printf("%d\n",dis[e]);}
前向星式
struct node{ int u,v,w; int next;}edge[40000];int head[40000];void init(){ memset(vis,0,sizeof(vis)); memset(head,0,sizeof(head)); for(int i = 0;i<n;i++) { dis[i] = INF; } t = 1;}int s,e;void add(int a,int b,int c){ edge[t].v = b; edge[t].w = c; edge[t].next = head[a]; head[a] = t++;}void SPFA(){ queue<int>q; q.push(s); vis[s] = true; dis[s] = 0; while(!q.empty()) { int p = q.front(); q.pop(); vis[p] = 0; if(head[p]) { for(int pp = head[p];pp!=0;pp = edge[pp].next) { if(dis[p] + edge[pp].w < dis[edge[pp].v]) { dis[edge[pp].v] = dis[p] + edge[pp].w ; if(!vis[edge[pp].v]) { q.push(edge[pp].v); vis[edge[pp].v] = true; } } } } } if(dis[e]<INF) printf("%d\n",dis[e]); else printf("-1\n");}
邻接链表式
struct node{ int u,v,w; node *next;}*head[40000];void init(){ memset(vis,0,sizeof(vis)); memset(head,NULL,sizeof(head)); for(int i = 0;i<n;i++) { dis[i] = INF; } t = 1;}int s,e;void add(int a,int b,int c){ node *p = new node; p->v = b; p->w = c; p->next = head[a]; head[a] = p;}void SPFA(){ queue<int>q; q.push(s); vis[s] = true; dis[s] = 0; while(!q.empty()) { int p = q.front(); q.pop(); vis[p] = 0; node *pp; for(pp = head[p];pp!=NULL;pp = pp->next) { if(dis[p] + pp->w < dis[pp->v]) { dis[pp->v] = dis[p] + pp->w; if(!vis[pp->v]) { q.push(pp->v); vis[pp->v] = true; } } } } if(dis[e]<INF) printf("%d\n",dis[e]);}
2 0
- 最短路算法汇总
- 最短路算法汇总
- JavaScript最短路算法
- 最短路算法总结
- 最短路算法总结
- 最短路 Dijkstra算法
- 最短路算法
- 最短路算法
- 最短路-Floyd算法
- 算法训练 最短路
- 最短路算法Dijkstra
- 最短路算法解析
- 最短路--SPFA算法
- 算法训练 最短路
- 最短路kruskal算法
- 最短路SPFA算法
- Dijkstra最短路算法
- 最短路算法
- Android.mk用法基础
- 逆序建立链表
- port linux & ramdisk
- switch的处理方法
- hdu 4831 Scenic Popularity(模拟)
- 最短路算法汇总
- 今天股市大跌的原因
- C#进度显示的简单实现
- smarty中自定义函数的使用(包括块方式)
- vs在release下调试时局部变量值错位修复
- android
- 批量下载音效
- CSS解决无空格太长的字母,数字不会自动换行的问题
- java反射理解