C++ 优化dijkstra实现
问题已编辑,现在我只想知道是否可以使用队列来改进算法。 我发现了使用dijkstra的混合成本最大流算法的实现: 将其粘贴到此处,以防它在互联网中丢失:C++ 优化dijkstra实现,c++,algorithm,matching,priority-queue,dijkstra,C++,Algorithm,Matching,Priority Queue,Dijkstra,问题已编辑,现在我只想知道是否可以使用队列来改进算法。 我发现了使用dijkstra的混合成本最大流算法的实现: 将其粘贴到此处,以防它在互联网中丢失: // Implementation of min cost max flow algorithm using adjacency // matrix (Edmonds and Karp 1972). This implementation keeps track of // forward and reverse edges separate
// Implementation of min cost max flow algorithm using adjacency
// matrix (Edmonds and Karp 1972). This implementation keeps track of
// forward and reverse edges separately (so you can set cap[i][j] !=
// cap[j][i]). For a regular max flow, set all edge costs to 0.
//
// Running time, O(|V|^2) cost per augmentation
// max flow: O(|V|^3) augmentations
// min cost max flow: O(|V|^4 * MAX_EDGE_COST) augmentations
//
// INPUT:
// - graph, constructed using AddEdge()
// - source
// - sink
//
// OUTPUT:
// - (maximum flow value, minimum cost value)
// - To obtain the actual flow, look at positive values only.
#include <cmath>
#include <vector>
#include <iostream>
using namespace std;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef long long L;
typedef vector<L> VL;
typedef vector<VL> VVL;
typedef pair<int, int> PII;
typedef vector<PII> VPII;
const L INF = numeric_limits<L>::max() / 4;
struct MinCostMaxFlow {
int N;
VVL cap, flow, cost;
VI found;
VL dist, pi, width;
VPII dad;
MinCostMaxFlow(int N) :
N(N), cap(N, VL(N)), flow(N, VL(N)), cost(N, VL(N)),
found(N), dist(N), pi(N), width(N), dad(N) {}
void AddEdge(int from, int to, L cap, L cost) {
this->cap[from][to] = cap;
this->cost[from][to] = cost;
}
void Relax(int s, int k, L cap, L cost, int dir) {
L val = dist[s] + pi[s] - pi[k] + cost;
if (cap && val < dist[k]) {
dist[k] = val;
dad[k] = make_pair(s, dir);
width[k] = min(cap, width[s]);
}
}
L Dijkstra(int s, int t) {
fill(found.begin(), found.end(), false);
fill(dist.begin(), dist.end(), INF);
fill(width.begin(), width.end(), 0);
dist[s] = 0;
width[s] = INF;
while (s != -1) {
int best = -1;
found[s] = true;
for (int k = 0; k < N; k++) {
if (found[k]) continue;
Relax(s, k, cap[s][k] - flow[s][k], cost[s][k], 1);
Relax(s, k, flow[k][s], -cost[k][s], -1);
if (best == -1 || dist[k] < dist[best]) best = k;
}
s = best;
}
for (int k = 0; k < N; k++)
pi[k] = min(pi[k] + dist[k], INF);
return width[t];
}
pair<L, L> GetMaxFlow(int s, int t) {
L totflow = 0, totcost = 0;
while (L amt = Dijkstra(s, t)) {
totflow += amt;
for (int x = t; x != s; x = dad[x].first) {
if (dad[x].second == 1) {
flow[dad[x].first][x] += amt;
totcost += amt * cost[dad[x].first][x];
} else {
flow[x][dad[x].first] -= amt;
totcost -= amt * cost[x][dad[x].first];
}
}
}
return make_pair(totflow, totcost);
}
};
//使用邻接实现最小代价最大流算法
//《黑客帝国》(Edmonds和Karp 1972)。此实现跟踪
//分别向前和向后边缘(因此您可以设置cap[i][j]=
//第[j][i]章。对于常规最大流量,将所有边缘成本设置为0。
//
//运行时间,O(| V | ^2)每次扩充的成本
//最大流量:O(| V | ^3)增大
//最小成本最大流量:O(| V | ^4*最大边缘成本)增量
//
//输入:
//-图形,使用AddEdge()构造
//-来源
//-水槽
//
//输出:
//-(最大流量值、最小成本值)
//-为获得实际流量,仅查看正值。
#包括
#包括
#包括
使用名称空间std;
typedef向量VI;
typedef向量VVI;
长L型;
typedef向量VL;
typedef向量VVL;
typedef对PII;
typedef载体VPII;
常量L INF=数值限制::max()/4;
结构MinCostMaxFlow{
int N;
VVL上限、流量、成本;
VI发现;
VL距离、pi、宽度;
VPII-dad;
MinCostMaxFlow(整数N):
N(N),上限(N,VL(N)),流量(N,VL(N)),成本(N,VL(N)),
发现(N)、距离(N)、π(N)、宽度(N)、dad(N){
无效附加值(起始整数、终止整数、上限、成本){
此->上限[从][到]=上限;
此->成本[从][到]=成本;
}
无效松弛(整数s、整数k、L上限、L成本、整数dir){
L val=距离[s]+pi[s]-pi[k]+成本;
如果(上限和下限<距离[k]){
dist[k]=val;
dad[k]=配对(s,dir);
宽度[k]=最小值(上限,宽度[s]);
}
}
L迪杰斯特拉(内特s,内特t){
填充(find.begin()、find.end()、false);
填充(dist.begin()、dist.end()、INF);
填充(width.begin(),width.end(),0);
距离[s]=0;
宽度[s]=INF;
而(s!=-1){
最佳整数=-1;
发现[s]=true;
对于(int k=0;k
我的问题是,是否可以通过在Dijkstra()中使用优先级队列来改进它。我试过了,但没能让它正常工作。
实际上我怀疑在Dijkstra,它应该在相邻节点上循环,而不是在所有节点上循环
非常感谢。当然Dijkstra的算法可以通过使用minheap来改进。在我们将一个顶点放入最短路径树并处理(即标记)所有相邻顶点后,我们的下一步是选择标签最小的顶点,而不是树中的顶点。
这就是minheap想到的地方。我们不是顺序扫描所有顶点,而是从堆中提取min元素并重新构造它,这需要O(logn)时间vs O(n)时间。请注意,堆将只保留那些尚未在最短路径树中的顶点。但是,如果我们更新它们的标签,我们应该能够以某种方式修改堆中的顶点。我不太确定使用优先级队列来实现Dijkstra的算法是否真的会提高运行时间,因为使用优先级队列可以减少找到与源之间距离最小的顶点所需的时间(O(log V)使用优先级队列vs.O(V)(在朴素实现中),它还增加了处理新边缘所需的时间(使用优先级队列vs.O(1)(在朴素实现中为O(log V))的时间) 因此,对于朴素的实现,运行时间是O(V^2+E) 但是,对于优先级队列实现,运行时间是O(V log V+E log V) 对于非常密集的图,E可以是O(V^2),这意味着原始实现的运行时间为O(V^2+V^2)=O(V^2),而优先级队列实现的运行时间为O(V log V+V^2 log V)=O(V^2 log V)。因此,如您所见,在密集图的情况下,优先级队列实现实际上具有更糟糕的最坏情况运行时间 鉴于编写上述实现的人员将边存储为邻接矩阵而不是使用邻接列表,编写此代码的人员似乎希望该图是一个具有O(V^2)边的稠密图,因此,在这里,他们将使用朴素的实现而不是优先级队列实现是有意义的
有关Dijkstra算法运行时间的更多信息,请继续阅读。1)不清楚您想要完成什么2)标题与算法不匹配。是最小成本还是最大流量?我要重新表述我的问题。