USACO 牛障碍赛:迪尼克的算法/对指针未注册的更改

USACO Cow Steeplechase: Dinic's Algorithm/Changes to Pointer Not Registering

本文关键字:算法 指针 注册 USACO      更新时间:2023-10-16

免责声明:并非我用来解决问题的所有代码都需要回答我的问题,但是如果需要,我将提供其余的。

问题(如果需要上下文(:http://www.usaco.org/index.php?page=viewproblem2&cpid=93

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <cmath>
using namespace std;
#define INF 1000000000
struct Edge{
    int from, to, cap, flow;
    Edge* backwards;
    Edge(int a, int b, int c, int d): from(a), to(b), cap(c), flow(d) {}
};
struct Dinic{
    int n, source, sink, dist [1000];
    queue<int> q;
    vector<Edge> adjacency [1000];
    bool blocked [1000];
    Dinic(int x): n(x), source(n++), sink(n++) { }
    void add(int v1, int v2, int c, int f){
        Edge e(v1, v2, c, f); Edge r(v2, v1, 0, 0);
        e.backwards = &r; r.backwards = &e;
        adjacency[v1].push_back(e); adjacency[v2].push_back(r);
    }
    bool bfs(){
        q = queue<int>(); fill_n(dist, 1000, -1); dist[sink] = 0; q.push(sink);
        while(q.size() > 0){
            int node = q.front(); q.pop();
            if(node == source) return true;
            for(int i = 0; i < adjacency[node].size(); i++){
                if(adjacency[node][i].backwards->cap > adjacency[node][i].backwards->flow && dist[adjacency[node][i].to] == -1){
                    dist[adjacency[node][i].to] = dist[node]+1;
                    q.push(adjacency[node][i].to);
                }
            }
        }
        return dist[source] != -1;
    }
    int dfs(int pos, int mini){
        if(pos == sink) return mini;
        int flowy = 0;
        for(int i = 0; i < adjacency[pos].size(); i++){
            int curr = 0;
            if(!blocked[adjacency[pos][i].to] && dist[adjacency[pos][i].to] == dist[pos]-1 && adjacency[pos][i].cap > adjacency[pos][i].flow){
                curr = dfs(adjacency[pos][i].to, min(mini-flowy, adjacency[pos][i].cap-adjacency[pos][i].flow));
                adjacency[pos][i].flow += curr; adjacency[pos][i].backwards->flow -= adjacency[pos][i].flow;
                flowy += curr;
            }
            if(flowy == mini) return flowy;
        }
        blocked[pos] = flowy != mini;
        return flowy;
    }
    int flow(){
        int ret = 0; fill_n(blocked, 1000, false);
        while(bfs()){
            fill_n(blocked, 1000, false);
            ret += dfs(source, INF);
            cout << ret << endl;
        }
        return ret;
    }
};

问题本质上缩小了缩小,以找到构成二分位图的顶点盖的最小顶点数量。我能够在代码的未见部分中成功构造了所述图形,但是我的问题在于在其上运行Dinic的算法。

当我这样做时,我会继续获得无限的循环,这源于" dfs(("方法中的错误。每当我尝试更新"向后边缘"指针时,它不会按预期保持更改,从而导致相同的路径一遍又一遍地。

我对使用指针非常陌生,在搜索数小时后,我无法找到与指针相关问题的解决方案或解释。

请帮助,并提前感谢!

编辑:在显示问题的代码段中添加。

Dinic solve(3);
solve.add(0, 3, 1, 0);
solve.adjacency[3][0].backwards->flow = 1;
cout << solve.adjacency[0][0].flow << endl; //prints out 0 instead of 1

您的示例突出显示的主要问题在add()方法中:

    void add(int v1, int v2, int c, int f){
        Edge e(v1, v2, c, f); Edge r(v2, v1, 0, 0);
        e.backwards = &r; r.backwards = &e;
        adjacency[v1].push_back(e); adjacency[v2].push_back(r);
    }

首先要观察您在堆栈上声明由er指定的Edge实例,因此,当变量在方法末尾的范围内时,它们的寿命结束。这确实与Java不同,Java只能在堆上分配对象,而您只有对它们的参考。

在每个Edge中,您将指针设置为其他堆栈分配的Edge,但是该指针值仅对尖(堆栈分配(对象的寿命有用;稍后将它们删除,即在该方法返回之后会产生不确定的行为。

此外,必须了解vector::push_back 创建其参数的副本。从这个意义上讲,这与Java的List.add()不同。这些副本包含backward Pointers 的值的副本,指出了原始指针指向的相同堆栈分配的对象。由于这些是与adjacency向量中的副本不同的对象,因此邻接向量的元素不会彼此指向。

也就是说,在方法返回之前,您有

  • e.backwards指向r
  • r.backwards指向e
  • (adjacency[v1]中的e的副本(.backwards还指向r
  • (adjacency[v2]中的r的副本(.backwards还指向e

因此,在您的示例中,执行solve.adjacency[3][0].backwards->flow = 1不会修改solve.adjacency[0][0]指定的对象,因为backwards指针没有指向该对象。(实际上,它曾经指出的对象的寿命已经结束,因此分配会产生未定义的行为。(因此,您不会观察到solve.adjacency[0][0]中的任何变化也就不足为奇了。

有几种方法可以解决这些问题,其中

  • 在堆上分配Edge对象,然后将指针存储在您的矢量中

  • 分配backward指向正确的矢量内Edges

后者可以在add()中实现,而无需修改其他任何内容;这应该做到:

    void add(int v1, int v2, int c, int f){
        Edge e(v1, v2, c, f);
        Edge r(v2, v1, 0, 0);
        adjacency[v1].push_back(e);
        adjacency[v2].push_back(r);
        adjacency[v1].back().backwards = &adjacency[v2].back();
        adjacency[v2].back().backwards = &adjacency[v1].back(); 
    }