用hashmap代替邻接矩阵实现maxflow算法

Implementing maxflow algorithm with a hashmap instead of adjacency matrix

本文关键字:实现 maxflow 算法 邻接矩阵 hashmap      更新时间:2023-10-16

我试图通过使用hashmap来表示图形而不是邻接矩阵来节省一些空间,我使用邻接矩阵运行相同的代码片段,一切都工作得很好,但是一旦我将数据结构更改为hashmap,它就会进入无限循环,无限循环是因为bsf函数定义返回boolean值,更具体地说,错误是行:if ((!visited[v]) && (rGraph[make_pair(u, v)] > 0))不知何故,如果条件不能正常工作,而我将rGraph表示为哈希映射。

我也想知道如果使用hashmap来表示图形是首选的方式?

代码如下:

bool bfs(map<pair<int, int>, int> rGraph, int s, int t, int parent[])
{
    // Create a visited array and mark all vertices as not visited
    bool visited[V];
    memset(visited, 0, sizeof(visited));
    // Create a queue, enqueue source vertex and mark source vertex
    // as visited
    queue <int> q;
    q.push(s);
    visited[s] = true;
    parent[s] = -1;
    // Standard BFS Loop
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int v=0; v<V; v++)
        {
            cout << "Value of graph at: " <<u << "  , " << v << " : " << rGraph[make_pair(u, v)] << "n";
            //cout << "!visited[v] : " << (!visited[v]) << "rGraph[u][v] : " << rGraph[make_pair(u, v)] << "n";
            cout << "if condition :  " << ((!visited[v]) && (rGraph[make_pair(u, v)] > 0)) << "n";
            if ((!visited[v]) && (rGraph[make_pair(u, v)] > 0))
            {
                q.push(v);
                parent[v] = u;
                visited[v] = true;
            }
        }
    }
    // If we reached sink in BFS starting from source, then return
    // true, else false
    return (visited[t] == true);
}
// Returns tne maximum flow from s to t in the given graph
int fordFulkerson(map<pair<int, int> , int> graph , int s, int t)
{
    int u, v;
    // Create a residual graph and fill the residual graph with
    // given capacities in the original graph as residual capacities
    // in residual graph
    map<pair<int, int>, int>rGraph; // Residual graph where rGraph[i][j] indicates
    // residual capacity of edge from i to j (if there
    // is an edge. If rGraph[i][j] is 0, then there is not)
    for (u = 0; u < V; u++){
        for (v = 0; v < V; v++){
            rGraph[make_pair(u, v)] = graph[make_pair(u, v)];
        }
    }
    int parent[V];  // This array is filled by BFS and to store path
    int max_flow = 0;  // There is no flow initially
    // Augment the flow while tere is path from source to sink
    while (bfs(rGraph, s, t, parent))
    {
        // Find minimum residual capacity of the edhes along the
        // path filled by BFS. Or we can say find the maximum flow
        // through the path found.
        int path_flow = INT_MAX;
        for (v=t; v!=s; v=parent[v])
        {
            u = parent[v];
            path_flow = min(path_flow, int(rGraph[make_pair(u, v)]));
        }
        // update residual capacities of the edges and reverse edges
        // along the path
        for (v=t; v != s; v=parent[v])
        {
            u = parent[v];
            rGraph[make_pair(u, v)] -= path_flow;
            rGraph[make_pair(u, v)] += path_flow;
        }
        // Add path flow to overall flow
        max_flow += path_flow;
    }
    // Return the overall flow
    return max_flow;
}
int main(){
    map< pair<int, int>, int > graph;
    graph[make_pair(0, 1)] = 16;
    graph[make_pair(0, 2)] = 13;
    graph[make_pair(1, 2)] = 10;
    graph[make_pair(1, 3)] = 12;
    graph[make_pair(2, 1)] = 4;
    graph[make_pair(2, 4)] = 14;
    graph[make_pair(3, 2)] = 9;
    graph[make_pair(3, 5)] = 20;
    graph[make_pair(4, 3)] = 7;
    graph[make_pair(4, 5)] = 4;*/

    cout << "The maximum possible flow is " << fordFulkerson(graph, 0, 5) << "n";
return 0;
}

邻接矩阵看起来像:

int graph[V][V] = { {0, 16, 13, 0, 0, 0},
                    {0, 0, 10, 12, 0, 0},
                    {0, 4, 0, 0, 14, 0},
                    {0, 0, 9, 0, 0, 20},
                    {0, 0, 0, 7, 0, 4},
                    {0, 0, 0, 0, 0, 0}};

首先,通过查看您的代码- 您没有使用hashmap -您正在使用map(读取:红黑树在大多数实现)。相当于"hashmap"的是unordered_map。然而,如果你想节省内存- ,你已经选择了正确的容器 (unordered_map可能比map消耗更多的内存- unordered_map (hashmap)需要为bucket提供连续的内存区域:当然所有bucket都不会被占用)。

现在是问题:当您执行rGraph[make_pair(u, v)] 时,您可能会在映射中创建一个新元素。索引操作符返回(参见cppreference):

  • 对索引make_pair(u, v)
  • 所指向的现有元素的引用
  • 如果make_pair(u, v)所指向的元素不存在- 它在该索引下创建一个新元素,并返回对该新元素的引用

如果你想检查一个元素是否存在于map/unordered_map中,你必须使用find方法:

auto p = make_pair(u, v)];
auto iter = rGraph.find(p);
if(iter != rGraph.end())
{//element 'rGraph[p]' exists
}
else
{//element 'rGraph[p]' does not exist
}

您还可以(潜在地)将插入新元素与检查新元素是否实际创建结合起来—这通常比单独使用insertfind更有效(参见cppreference):

auto p = make_pair(u, v)];
auto res = rGraph.insert(make_pair(p,1)); //insert value '1'
if(res.second)
{//new element was inserted
}
else
{//element already existed
}
//here res.first is an iterator pointing to the element rGraph[p] - newly inserted or not

您应该使用count或find方法来检查映射中的项是否存在,而不是使用操作符[],因为如果不存在,它将构造一个新项。所以改变

rGraph[make_pair(u, v)]>0

rGraph.count(make_pair(u, v))>0

另外,我可能建议通过引用传递任何大对象(例如map)。此外,正如这里提到的,您可以使用"unordered_map",它是一个散列表,而不是"map",它是一个树,因为您不需要对映射进行排序。