Add functions to find minimum cut from a maximum flow
This commit is contained in:
44
src/flow.c
44
src/flow.c
@@ -1,7 +1,6 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include "gtsp.h"
|
#include "gtsp.h"
|
||||||
#include "flow.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int flow_find_max_flow(
|
int flow_find_max_flow(
|
||||||
@@ -58,6 +57,9 @@ int flow_find_max_flow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rval = flow_mark_reachable_nodes(digraph, residual_caps, from);
|
||||||
|
abort_if(rval, "flow_mark_reachable_nodes failed");
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
if (path_edges) free(path_edges);
|
if (path_edges) free(path_edges);
|
||||||
if (residual_caps) free(residual_caps);
|
if (residual_caps) free(residual_caps);
|
||||||
@@ -152,3 +154,43 @@ int flow_find_augmenting_path(
|
|||||||
if (queue) free(queue);
|
if (queue) free(queue);
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int flow_mark_reachable_nodes(
|
||||||
|
struct Graph *graph, double *residual_caps, struct Node *from)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
|
||||||
|
struct Node **stack;
|
||||||
|
int stack_top = 0;
|
||||||
|
|
||||||
|
stack = (struct Node**) malloc(graph->node_count * sizeof(struct Node*));
|
||||||
|
abort_if(!stack, "could not allocate stack");
|
||||||
|
|
||||||
|
for (int i = 0; i < graph->node_count; i++)
|
||||||
|
graph->nodes[i].mark = 0;
|
||||||
|
|
||||||
|
from->mark = 1;
|
||||||
|
stack[stack_top++] = from;
|
||||||
|
|
||||||
|
while(stack_top > 0)
|
||||||
|
{
|
||||||
|
struct Node *n = stack[--stack_top];
|
||||||
|
|
||||||
|
for (int j = 0; j < n->degree; j++)
|
||||||
|
{
|
||||||
|
struct Edge *e = n->adj[j].edge;
|
||||||
|
struct Node *neighbor = n->adj[j].neighbor;
|
||||||
|
|
||||||
|
if(neighbor->mark) continue;
|
||||||
|
if(residual_caps[e->index] <= 0) continue;
|
||||||
|
|
||||||
|
stack[stack_top++] = neighbor;
|
||||||
|
neighbor->mark = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
CLEANUP:
|
||||||
|
if(stack) free(stack);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
17
src/graph.c
17
src/graph.c
@@ -179,3 +179,20 @@ void get_delta(
|
|||||||
for (int i = 0; i < island_node_count; i++)
|
for (int i = 0; i < island_node_count; i++)
|
||||||
marks[island_nodes[i]] = 0;
|
marks[island_nodes[i]] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_cut_edges_from_marks(
|
||||||
|
struct Graph *graph, int *cut_edges_count, struct Edge **cut_edges)
|
||||||
|
{
|
||||||
|
*cut_edges_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < graph->edge_count; ++i)
|
||||||
|
{
|
||||||
|
struct Edge *e = &graph->edges[i];
|
||||||
|
struct Node *from = e->from;
|
||||||
|
struct Node *to = e->to;
|
||||||
|
if (from->mark && !to->mark)
|
||||||
|
cut_edges[(*cut_edges_count)++] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -70,4 +70,7 @@ void get_delta(
|
|||||||
int graph_build_directed_from_undirected
|
int graph_build_directed_from_undirected
|
||||||
(const struct Graph *graph, struct Graph *digraph);
|
(const struct Graph *graph, struct Graph *digraph);
|
||||||
|
|
||||||
|
int get_cut_edges_from_marks(
|
||||||
|
struct Graph *graph, int *cut_edges_count, struct Edge **cut_edges);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
30
src/main.c
30
src/main.c
@@ -29,6 +29,8 @@ int test_max_flow()
|
|||||||
double *flow = 0;
|
double *flow = 0;
|
||||||
double flow_value;
|
double flow_value;
|
||||||
|
|
||||||
|
struct Edge **cut_edges = 0;
|
||||||
|
|
||||||
FILE *f = fopen("tmp/flow.in", "r");
|
FILE *f = fopen("tmp/flow.in", "r");
|
||||||
abort_if(!f, "could not open input file");
|
abort_if(!f, "could not open input file");
|
||||||
|
|
||||||
@@ -83,10 +85,36 @@ int test_max_flow()
|
|||||||
struct Edge *e = &graph.edges[i];
|
struct Edge *e = &graph.edges[i];
|
||||||
if (flow[e->index] <= 0) continue;
|
if (flow[e->index] <= 0) continue;
|
||||||
|
|
||||||
log_info(" %d %d %6.2f / %6.2f\n", e->from->index, e->to->index, flow[e->index], capacities[e->index]);
|
log_info(" %d %d %6.2f / %6.2f\n", e->from->index, e->to->index,
|
||||||
|
flow[e->index], capacities[e->index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_info("Nodes reachable from origin on residual graph:\n");
|
||||||
|
for (int i = 0; i < graph.node_count; i++)
|
||||||
|
{
|
||||||
|
struct Node *n = &graph.nodes[i];
|
||||||
|
if(n->mark)
|
||||||
|
log_info(" %d\n", n->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cut_edges_count = 0;
|
||||||
|
cut_edges = (struct Edge**) malloc(graph.edge_count * sizeof(struct Edge*));
|
||||||
|
abort_if(!cut_edges, "could not allocate cut_edges");
|
||||||
|
|
||||||
|
rval = get_cut_edges_from_marks(&graph, &cut_edges_count, cut_edges);
|
||||||
|
abort_if(rval, "get_cut_edges_from_marks failed");
|
||||||
|
|
||||||
|
log_info("Min cut edges:\n");
|
||||||
|
for (int i = 0; i < cut_edges_count; i++)
|
||||||
|
{
|
||||||
|
struct Edge *e = cut_edges[i];
|
||||||
|
if(capacities[e->index] <= 0) continue;
|
||||||
|
log_info(" %d %d\n", e->from->index, e->to->index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
CLEANUP:
|
CLEANUP:
|
||||||
|
if(cut_edges) free(cut_edges);
|
||||||
if (capacities) free(capacities);
|
if (capacities) free(capacities);
|
||||||
if (edges) free(edges);
|
if (edges) free(edges);
|
||||||
if (flow) free(flow);
|
if (flow) free(flow);
|
||||||
|
|||||||
Reference in New Issue
Block a user