191 lines
4.4 KiB
Plaintext
191 lines
4.4 KiB
Plaintext
Christian Sinschek
|
|
|
|
fordfulk.tri berechnet den maximalen Fluss in einem gerichteten Flussgraphen
|
|
Eingabeformat:
|
|
Input -> Knotenzahl Kantenzahl Kanten
|
|
Kanten-> Startpunkt Flussmenge Endpunkt
|
|
{alle nicht-Terminale nur auf rechten Seiten} -> int
|
|
|
|
z.B. gut lesbar so zu schreiben, da Triangle auf Zeilenumbrüche "wartet"
|
|
4 3
|
|
0 3 1
|
|
1 2 2
|
|
1 2 3
|
|
|
|
Arrays in Triangle- auch der neuen Version- können leider mit allen Verschachtelungen nur eine Größe von 225 Feldern haben, daher sind die Netzwerke auf 15 Knoten, also eine 15x15- Flussmatrix beschränkt.
|
|
|
|
Ausgabe ist einfach der Maxflow.
|
|
|
|
Hier der C-Quellcode von
|
|
http://www.aduni.org/courses/algorithms/courseware/handouts/Reciation_09.html
|
|
|
|
(unten weiter)
|
|
|
|
// The Ford-Fulkerson Algorithm in C
|
|
|
|
#include <stdio.h>
|
|
Basic Definitions
|
|
|
|
#define WHITE 0
|
|
#define GRAY 1
|
|
#define BLACK 2
|
|
#define MAX_NODES 1000
|
|
#define oo 1000000000
|
|
|
|
|
|
|
|
// Declarations
|
|
|
|
int n; // number of nodes
|
|
int e; // number of edges
|
|
int capacity[MAX_NODES][MAX_NODES]; // capacity matrix
|
|
int flow[MAX_NODES][MAX_NODES]; // flow matrix
|
|
int color[MAX_NODES]; // needed for breadth-first search
|
|
int pred[MAX_NODES]; // array to store augmenting path
|
|
|
|
int min (int x, int y) {
|
|
return x<y ? x : y; // returns minimum of x and y
|
|
}
|
|
|
|
|
|
// A Queue for Breadth-First Search
|
|
|
|
int head,tail;
|
|
int q[MAX_NODES+2];
|
|
|
|
void enqueue (int x) {
|
|
q[tail] = x;
|
|
tail++;
|
|
color[x] = GRAY;
|
|
}
|
|
|
|
int dequeue () {
|
|
int x = q[head];
|
|
head++;
|
|
color[x] = BLACK;
|
|
return x;
|
|
}
|
|
|
|
|
|
|
|
// Breadth-First Search for an augmenting path
|
|
|
|
int bfs (int start, int target) {
|
|
int u,v;
|
|
for (u=0; u<n; u++) {
|
|
color[u] = WHITE;
|
|
}
|
|
head = tail = 0;
|
|
enqueue(start);
|
|
pred[start] = -1;
|
|
while (head!=tail) {
|
|
u = dequeue();
|
|
// Search all adjacent white nodes v. If the capacity
|
|
// from u to v in the residual network is positive,
|
|
// enqueue v.
|
|
for (v=0; v<n; v++) {
|
|
if (color[v]==WHITE && capacity[u][v]-flow[u][v]>0) {
|
|
enqueue(v);
|
|
pred[v] = u;
|
|
}
|
|
}
|
|
}
|
|
// If the color of the target node is black now,
|
|
// it means that we reached it.
|
|
return color[target]==BLACK;
|
|
}
|
|
|
|
|
|
// Ford-Fulkerson Algorithm
|
|
|
|
int max_flow (int source, int sink) {
|
|
int i,j,u;
|
|
// Initialize empty flow.
|
|
int max_flow = 0;
|
|
for (i=0; i<n; i++) {
|
|
for (j=0; j<n; j++) {
|
|
flow[i][j] = 0;
|
|
}
|
|
}
|
|
// While there exists an augmenting path,
|
|
// increment the flow along this path.
|
|
while (bfs(source,sink)) {
|
|
// Determine the amount by which we can increment the flow.
|
|
int increment = oo;
|
|
for (u=n-1; pred[u]>=0; u=pred[u]) {
|
|
increment = min(increment,capacity[pred[u]][u]-flow[pred[u]][u]);
|
|
}
|
|
// Now increment the flow.
|
|
for (u=n-1; pred[u]>=0; u=pred[u]) {
|
|
flow[pred[u]][u] += increment;
|
|
flow[u][pred[u]] -= increment;
|
|
}
|
|
max_flow += increment;
|
|
}
|
|
// No augmenting path anymore. We are done.
|
|
return max_flow;
|
|
}
|
|
|
|
|
|
|
|
// Reading the input file and the main program
|
|
|
|
void read_input_file() {
|
|
int a,b,c,i,j;
|
|
FILE* input = fopen("mf.in","r");
|
|
// read number of nodes and edges
|
|
fscanf(input,"%d %d",&n,&e);
|
|
// initialize empty capacity matrix
|
|
for (i=0; i<n; i++) {
|
|
for (j=0; j<n; j++) {
|
|
capacity[i][j] = 0;
|
|
}
|
|
}
|
|
// read edge capacities
|
|
for (i=0; i<e; i++) {
|
|
fscanf(input,"%d %d %d",&a,&b,&c);
|
|
capacity[a][b] = c;
|
|
}
|
|
fclose(input);
|
|
}
|
|
|
|
int main () {
|
|
read_input_file();
|
|
printf("%d\n",max_flow(0,n-1));
|
|
return 0;
|
|
}
|
|
|
|
|
|
Beim Programmieren war mir nicht bewusst, dass Triangle ein Konzept lokaler Sichbarkeit globaler Variablen haben könnte, deshalb werden alle Variablen z. T. redundant übergeben. Ob Compiler-Optimierungen da sinnvoll eingreifen weis ich erstn, wenn ich weiss wie wir den Compiler optimieren (der Fall ist doch recht dämlich), aber ich habe es dennoch mal so gelassen.
|
|
Größtes "Problem" des Algorithmus ist seine geringe Laufzeit, zumindest funktionale Äquivalenz der Compiler sollte sollte ich zeigen lassen.
|
|
|
|
Beispieleingaben, zu machen auch durch einfaches c+p
|
|
6 9
|
|
0 5 1
|
|
0 7 2
|
|
1 7 2
|
|
1 4 3
|
|
2 3 4
|
|
2 3 3
|
|
3 4 4
|
|
3 5 5
|
|
4 6 5
|
|
|
|
9 15
|
|
0 8 1
|
|
1 3 3
|
|
2 3 4
|
|
4 2 6
|
|
5 2 7
|
|
7 5 8
|
|
3 2 6
|
|
6 4 8
|
|
1 4 4
|
|
4 4 7
|
|
0 7 2
|
|
2 2 5
|
|
2 2 7
|
|
4 8 8
|
|
1 5 6
|
|
|
|
Die Beispiele entsprechen der GDI3 vom WS 04/05, Skript 3, Folie 29/30 links oben und Übung/Musterlösung 5 |