最短路径小结
Dijkstra不能解决负权图:
因为Dijkstra是贪心的,每次都找一个距源点最近的点d[u],然后将该距离定为这个点到源点的最短路径;但如果存在负权边,那后来就有可能通过并不是距源点最近的一个次优点dd,再通过这个负权边L(L<0),使得路径之和更小(dd+L<d),则dd+L成为最短路径,并不是d。然后各个节点便不断入栈,更新最距离,距离会任意的小,最后导致陷入死循环,这样Dijkstra就被囧掉了。比如,假设有顶1,2,3,边12的权值是5,边13的权值是3,边23的权值是-4,计算从a到c的最短路径。disto[1]=0->(-7)+3=-4->(-11)+5=6...disto[2]=5->1+(-4)=-3->(-7)+(-4)=-11...disto[3]=3->5+(-4)=1->(-3)+(-4)=-7...死循环了
Dijkstra模板
void Dijkstra(int id) { memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) d[i]=g[id][i]; d[id]=0,vis[id]=1; for(int i=2;i<=n;i++){ int min=inf,k; for(int j=1;j<=n;j++){ if(!vis[j]&&d[j]<min){ min=d[j]; k=j; } } d[k]=min,vis[k]=1; for(int j=1;j<=n;j++){ if(!vis[j]&&g[k][j]!=inf){ if(d[j]>d[k]+g[k][j]) d[j]=d[k]+g[k][j]; } } } }
同时Bellman Ford算法也可以计算最长路,只需建图时将权值改为相反数即可,
那么d[i]得保存的将是最长距离的相反数(PS:最大生成树同理)
Bellman Ford模板 参考链接
int Bellman_Ford() { for(int i=1;i<=n;i++) d[i]=inf; d[1]=0; for(int i=1;i<n;i++){ for(int j=0;j<m;j++){ int u=edge[j].u; int v=edge[j].v; int w=edge[j].w; if(d[u]<inf&&d[u]+w<d[v]) d[v]=d[u]+w; } } for(int j=0;j<m;j++){//检测负环 int u=edge[j].u; int v=edge[j].v; int w=edge[j].w; if(d[u]<inf&&d[u]+w<d[v]) return 0; } return 1; }
Spfa不能解决负环图,当某个节点入队超过n次则存在负环.
Spfa模板,不过加上vis[maxn]数组好像并没有用,QAQ,难道是测试数据太小?
void Spfa(int u) { for(int i=s;i<=t;i++) d[i]=i==u?0:-inf; que.push(u); while(!que.empty()){ u=que.front(); que.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=e[i].next){ int v=e[i].to; int w=e[i].wt; if(d[v]<d[u]+w){//d[u]!=-inf可有可无 d[v]=d[u]+w; if(vis[v]) continue; vis[v]=1; que.push(v); } } } }

浙公网安备 33010602011771号