質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

235閲覧

フォードファルカーソンのプログラムの「F」の役目を知りたい。

SmaSTATION

総合スコア29

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2023/11/14 06:27

実現したいこと

以下プログラムの変数「F」(70~73行目)について何を示しているのかを知りたいです。
解説によると「スタートからゴールまでの各辺の最小容量」との記載があったのですが、よくわからないです。

前提

以下、該当プログラムです。

入力データ

6 9 0 1 5 0 3 5 1 3 37 1 2 4 3 2 3 3 4 9 2 4 56 2 5 9 4 5 2

該当のソースコード

C++

1#include <iostream> 2#include <vector> 3using namespace std; 4 5// グラフを表す構造体 6struct Graph { 7 // 辺を表す構造体 8 // rev: 逆辺 (to, from) が G[to] の中で何番目の要素か 9 // cap: 辺 (from, to) の容量 10 struct Edge { 11 int rev, from, to, cap; 12 Edge(int r, int f, int t, int c) : 13 rev(r), from(f), to(t), cap(c) {} 14 }; 15 16 // 隣接リスト 17 vector<vector<Edge>> list; 18 19 // N: 頂点数 20 Graph(int N = 0) : list(N) { } 21 22 // グラフの頂点数取得 23 size_t size() { 24 return list.size(); 25 } 26 27 // Graph インスタンスを G として, 28 // G.list[v] を G[v] と書けるようにしておく 29 vector<Edge> &operator [] (int i) { 30 return list[i]; 31 } 32 33 // 辺 e = (u, v) の逆辺 (v, u) を取得する 34 Edge& redge(const Edge &e) { 35 return list[e.to][e.rev]; 36 } 37 void run_flow(Edge &e, int f) { 38 e.cap -= f; 39 redge(e).cap += f; 40 } 41 42 43 void addedge(int from, int to, int cap) { 44 //cout<<"From="<<from<<endl; 45 /*cout<<"To="<<to<<endl; 46 cout<<"Cap="<<cap<<endl;*/ 47 int fromrev = (int)list[from].size(); 48 //cout << "fromrev="<<fromrev<<endl; 49 int torev = (int)list[to].size(); 50 //cout << "torev="<<torev<<endl; 51 list[from].push_back(Edge(torev, from, to, cap)); 52 list[to].push_back(Edge(fromrev, to, from, 0)); 53 } 54}; 55 56struct FordFulkerson { 57 static const int INF = 1 << 30; 58 vector<int> seen; 59 60 FordFulkerson() { } 61 62 // 残余グラフ上で s-t パスを見つける (深さ優先探索) 63 // 返り値は s-t パス上の容量の最小値 (見つからなかったら 0) 64 // f: s から v へ到達した過程の各辺の容量の最小値 65 int fodfs(Graph &G, int v, int t, int f) { 66 cout<<"V="<<v<<endl; //スタート 67 cout<<"T="<<t<<endl; //ゴール 68 cout<<"F="<<f<<endl; 69 // 終端 t に到達したらリターン 70 if (v == t) return f; 71 72 // 深さ優先探索 73 seen[v] = true; 74 for (auto &e : G[v]) { 75 cout<<"Seen[e.to]="<<seen[e.to]<<endl; 76 if (seen[e.to]) continue; 77 78 79 cout<<"e.cap="<<e.cap<<endl; 80 if (e.cap == 0) continue; 81 82 83 int flow = fodfs(G, e.to, t, min(f, e.cap)); 84 cout << "Flow=" <<flow << endl; 85 86 // s-t パスが見つからなかったら次辺を試す 87 if (flow == 0) continue; 88 89 // 辺 e に容量 flow のフローを流す 90 G.run_flow(e, flow); 91 92 // s-t パスを見つけたらパス上最小容量を返す 93 return flow; 94 } 95 96 // s-t パスが見つからなかったことを示す 97 return 0; 98 } 99 100 // グラフ G の s-t 間の最大流量を求める 101 // ただしリターン時に G は残余グラフになる 102 int solve(Graph &G, int s, int t) { 103 int res = 0; 104 105 // 残余グラフに s-t パスがなくなるまで反復 106 while (true) { 107 seen.assign((int)G.size(), 0); 108 int flow = fodfs(G, s, t, INF); 109 110 // s-t パスが見つからなかったら終了 111 if (flow == 0) return res; 112 113 // 答えを加算 114 res += flow; 115 } 116 117 // no reach 118 return 0; 119 } 120}; 121 122int main() { 123 // グラフの入力 124 // N: 頂点数、M: 辺数 125 int N, M; 126 cin >> N >> M; 127 Graph G(N); 128 for (int i = 0; i < M; ++i) { 129 int u, v, c; 130 cin >> u >> v >> c; 131 132 // 容量 c の辺 (u, v) を張る 133 G.addedge(u, v, c); 134 } 135 136 // フォード・ファルカーソン法 137 FordFulkerson ff; 138 int s = 0, t = N - 1; 139 cout << ff.solve(G, s, t) << endl; 140}

試したこと

  • 関係しそうな変数の出力(V,T)

➡Vが深さ優先の始点、Tが終点というのはわかりました。だが、Fの解決には結びつかず...。

  • 深さ優先の際に使う変数の出力

➡Seen[e.to]やe.capもどういう役割かはわかりませんが、関係なさそう...。

出力(一部抜粋)

V=0 T=5 F=1073741824 Seen[e.to]=0 e.cap=5 V=1 T=5 F=5 Seen[e.to]=1 Seen[e.to]=0 e.cap=37 V=3 T=5 F=5 Seen[e.to]=1 Seen[e.to]=1 Seen[e.to]=0 e.cap=3 V=2 T=5 F=3 Seen[e.to]=1 Seen[e.to]=1 Seen[e.to]=0 e.cap=56 V=4 T=5 F=3 Seen[e.to]=1 Seen[e.to]=1 Seen[e.to]=0 e.cap=2 V=5 T=5 F=2 Flow=2 Flow=2 Flow=2 Flow=2 Flow=2

補足情報(FW/ツールのバージョンなど)

抽象的な疑問で申し訳ないですが、𠮟咤激励含めて些細なことでも構いませんので、よろしくお願いいたします。
※実行環境:Paiza

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

「ChatGPT(GPT-4)]により生成された文章です」

このコードは、Ford-Fulkerson アルゴリズムを使用して、与えられたグラフにおける最大フロー問題を解くためのものです。具体的には、ソース(始点)からシンク(終点)までの間で流れることができる最大のフロー量を計算します。

あなたが言及した変数 F(70〜73行目にある f)は、Ford-Fulkerson アルゴリズムにおける核心的な概念です。この変数 f は、ある経路(パス)における「残余容量(residual capacity)」の最小値を保持します。

残余容量(Residual Capacity)とは
残余容量は、ある経路の各辺において、まだどれだけのフローを追加で流すことができるかを示します。この値は、その辺の容量と、既にその辺を通っているフローの量の差によって決まります。

変数 F の役割
アルゴリズムは、ソース(始点)からシンク(終点)までの様々な経路を探索します。各経路を探索する際に、その経路に含まれる辺の中で最も小さい残余容量(すなわち最も「狭い」部分)が、その経路を通過できるフローの量を決定します。

fodfs関数では、再帰的に呼び出されるたびに、変数 f がその時点での経路の最小残余容量として更新されます。これにより、アルゴリズムは各経路における最大の可能フロー量を見つけることができます。

アルゴリズムのプロセス
ソースからシンクへのパスを見つけます。
そのパスに沿って最小の残余容量(f)を見つけます。
そのフローをパスに沿って流し、フローを反映してグラフ(残余グラフ)を更新します。
もうパスが見つからなくなるまで、このプロセスを繰り返します。
最終的に、これらのパスに沿って流されたフローの合計が、ソースからシンクまでの最大フローとなります。

投稿2023/11/14 06:45

quiz

総合スコア269

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問