首页 > 代码库 > 最短路问题
最短路问题
Bellman-Ford算法:(单源最短路)
从起点s出发到顶点i的最短距离d[i]
d[i] = min{d[j]+(从j到i的边的权值|)}
d[s] = 0;d[i] = INF; 依次更新最短路径。
实现:
const int MAX = 100; const int INF = 1<<30; struct edge{ int from,to,cost; }; edge es[MAX]; int n; int d[MAX]; int V,E; void slove(int s){ fill(d,d+V,INF); d[s] = 0; while(true){ bool update = false; for(int i=0;i<E;i++){ edge e = es[i]; if(d[e.from]!=INF && d[e.to]>d[e.from]+e.cost){ d[e.to] = d[e.from] +e.cost; update = true; } } if(!update) break; } } //判断是否存在着负环 bool negative_loop(){ memset(d,0,sizeof(d)); for(int i=0;i<V;i++){ for(int j=0;j<E;j++){ edge e = es[j]; if(d[e.to]>d[e.from]+e.cost){ d[e.to] = d[e.from] +e.cost; //如果最后一次仍然更新 说明存在着负数的权值 if(i==V-1) return true; } } } return false; }
Dijkstra算法:
前提条件:不存在负环。
(1) 找到最短距离已经确定的点,从这个点出发更新相邻顶点的最短距离
(2)之后就不用需要关心(1)中已经确定的点了
图解:
算法过程:
a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。
b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。
c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。
d.重复步骤b和c直到所有顶点都包含在S中。
const int MAX =100 ; const int INF = 1<<30; int cost[MAX][MAX];//cost[u][v] 表示e=(u,v)的权值 int d[MAX]; bool used[MAX];//顶点是否已经确定 int V; void dijkstra(int s){ fill(d,d+V;INF); fill(used,used+V,false); d[s] = 0; while(true){ int v = -1; for(int u=0;u<V;u++){ if(!used[u] && (v==-1 || d[u]<d[v])) v = u; } if(v==-1) break; used[v] = true; for(int u=0;i<V;i++){ d[u] = min(d[u],d[v]+cost[v][u]); } } }需要优化的是数值的插入和取出最小值的操作,所以使用堆结构,所以使用STL里面的优先队列正好。
代码:
struct edge{int from ,to,cost}; const int MAX =100 ; const int INF = 1<<30; typedef pair<int,int> P;//first 最短距离,second 编号 int V; vector<int> G[MAX]; int d[MAX]; void dijkstra(int s){ fill(d,d+V;INF); d[s] = 0; priority_queue<P, vecotr<P>, greater<P> > que; que.push(P(0,s); while(!qie.empty()){ P p = que.top(); que.pop(); int v = p.second; if(d[v]<p.first){ continue; } for(int i=0;i<G[v].size();i++){ egde e = G[v][i]; if(d[e.to]>d[e.from]+cost){ d[e.to] = d[e.from]+cost; que.push(P(d[e.to],e.to)); } } } }
Floyd-Warshall算法:
任意两点(i,j)之间的最短路 DP解决:
任一两点之间的距离 取决于是否经过k点:
(1) 不经过K点:
d[k][i][j] = d[k-1][i][j];
(2) 经过K点
d[k][i][k] = d[k-1][i][k]+d[k-1][k][j]
所以:
d[k][i][j] = min(d[k-1][i][j],d[k-1][i][k]+d[k-1][k][j]);
使用一个DP数组:
dp[i][k] = min(dp[i][j],dp[i][k]+dp[k][j]);
实现:
int dp[MAX][MAX]; int V; void warshall_floyd(){ for(int k=0;k<V;k++) for(int i = 0;i<V;i++) for(int j=0;j<v;j++) dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]); }
最短路问题
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。