免責事項:私の質問に答えるために使用したコードのすべてが必要ではありませんが、必要に応じて残りの部分を提供します。USACO Cow Steeplechase:Dinicのアルゴリズム/ポインタの変更が登録されていない
通報(コンテキストが必要な場合):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()」メソッドのエラーに起因して、無限ループが発生しています。 「後ろ向きエッジ」ポインタを更新しようとすると、意図したとおりに変更が維持されず、結果として同じパスが何度も繰り返されます。
私はポインタを使用するのが非常に新しいので、数時間の検索の後にポインタに関する問題の解決策や説明を見つけることができませんでした。
ご協力いただきありがとうございます。
EDIT:問題を表示するコードの一部に追加されました。
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
のインスタンスを宣言していることを最初に観察し、そして:あなたの例で強調
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
ポインタの更新とそれがポイントするオブジェクトの更新を区別するように注意してください。あなたはその問題を前者のように記述しますが、最初にそれらを設定した後には、逆方向ポインタ自体を修正しようとしません。 –
確率は非常に良いですが、すべてのコードをコンテキストに欲しがっていませんが、誤った動作を反復的に示す簡単なテストプログラム[mcve]は金の価値があります。実際にMCVEを制作することによって、あなた自身の質問に答えたことが分かるかもしれません。 – user4581301
あなたの実装は少し奇妙です。 Dinicは* directed *グラフのアルゴリズムですが、前方エッジごとに後方エッジを追加するという意味では、*無向写*を構築しているようです。これは問題の一部である可能性があります。グラフに真の2エッジループがある場合は、特に問題の一部になる可能性があります。 –