USACO 牛障碍赛:迪尼克的算法/对指针未注册的更改
USACO Cow Steeplechase: Dinic's Algorithm/Changes to Pointer Not Registering
免责声明:并非我用来解决问题的所有代码都需要回答我的问题,但是如果需要,我将提供其余的。
问题(如果需要上下文(: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); }
首先要观察您在堆栈上声明由e
和r
指定的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();
}
- 使用指针算法修改函数中的 2D 数组
- 通过指针算法计算数组长度
- 是否有一种 STL 算法可以最后找到,但它也适用于指针?
- 由于指针算法错误,代码在 memcpy 中崩溃
- 在 c++ 中使用指针算法
- 通过指针算法访问结构数据成员
- 使用字符** argv 时如何避免指针算法
- 通过指针算法调用结构的结构属性
- R-->cpp 如何让C++指针与 sourceCpp (Bellman Ford 算法)
- 是什么让这种易失性打破了结构的指针算法?
- 使用指针算法调用结构内的结构数组
- USACO 牛障碍赛:迪尼克的算法/对指针未注册的更改
- 指针算法:*p++ 和 (*p)++ 等等
- 指针算法是否适用于迭代器?
- 你不能在 void 指针上使用指针算法,那么 void 指针数组是如何工作的呢?
- 使用指针算法搜索 2D 数组
- 未检测到越界指针算法?
- 指针似乎迷失在递归算法中
- 为什么这种递归子集和算法会导致指针分配错误
- 分类算法和对象指针的问题