经典算法
单源最短路:
1.Bellman_ford(可判负环,可有负边)
d[i]表示起点S到i的最短路,那么d[i]=min{d[j]+w[j][i]}且存在j->i的边代价为w[j][i]
经过证明如果不存在负圈最多通过V-1次松弛就可以完成复杂度O(V*E)(V为结点数,E为边数)
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include
View Code 判负环:看一下是不是多于V-1次松弛,如果有则存在负环
1 bool HaveNagativeLoop(){ 2 memset(d,0,sizeof(d)); 3 for(int i=0;i d[e.from]+e.w){ 7 d[e.to] = d[e.from]+e.w; 8 if(i==V-1)return true; 9 }10 }11 }12 return false;13 }
View Code 2.dijkstra(无负边)
对于上述的d[i]=min{d[j]+w[j][i]}如果d[j]当前值不是d[j]能达到的最小值那么显然在后面d[i]还将更新,如何避免这种情况
选择d[j]已经是最小,即S->j的最短距离不再更新,如何选取?每次选择距离最短且未被使用的结点,用这个结点对其他节点进行松弛复杂度O(V*V)
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include
View Code 来优化一下上面的算法,每次需要选择最短的一个结点,这个可以使用一个优先队列来维护当前所有边里面权值最小的边,所以算法复杂度变为O(V*log(E))
使用邻接表存储图比较容易写
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include
View Code 3.floyd(任意两点的最短路,可有负边)
dp的思想 d[k+1][i][j]表示从0~k 里面选择中间结点从i到j的最短距离 那么当k为-1时d[0][i][j]=w[i][j]
考虑如何转移 从0~k-1中间选到0~k中选新的方案有两种情况:
不经过第k个结点 那么 d[k+1][i][j]=d[k][i][j]
经过第k个结点 那么d[k+1][i][j] = d[k][i][k]+d[k][k][j]
则方程为d[k+1][i][j]=min{ d[k][i][j],d[k][i][k]+d[k][k][j]}
可以使用滚动数组来优化空间,由于d[k+1][][]只与d[k][][]有关,所以只要保证k是从小到大枚举的就可以节省以为空间,复杂度为O(V*V*V)
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include
View Code