Cod sursa(job #2809033)

Utilizator SaaNaSaa Na SaaNa Data 25 noiembrie 2021 20:30:39
Problema Flux maxim Scor 0
Compilator c-64 Status done
Runda Arhiva educationala Marime 11.82 kb
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include "dynamic_trees/dynamic_trees.h"

#define INP_FILE stdin
#define OUT_FILE stdout

typedef struct queue_cell {
    int value;
    struct queue_cell *next;
} QCell, *TQCell;

typedef struct squeue {
    TQCell head;
    TQCell tail;
} Queue, *TQueue;

void enqueue(TQueue queue, int val)
{
    TQCell cell = (TQCell) malloc(sizeof(*cell));
    cell->value = val;
    cell->next = NULL;
    if (queue->head == NULL) {
        queue->head = cell;
        queue->tail = cell;

        return;
    }

    queue->tail->next = cell;
    queue->tail = cell;

    return;
}

int dequeue(TQueue queue)
{
    int value = queue->head->value;

    if (queue->head == queue->tail) {
        free(queue->head);
        queue->head = queue->tail = NULL;

        return value;
    }

    TQCell aux = queue->head;
    queue->head = queue->head->next;
    free(aux);

    return value;
}

void destroy_queue(TQueue queue)
{
    while (queue->head != NULL) {
        dequeue(queue);
    }
    free(queue);

    return;
}

typedef struct dgraph_edge {
    int id;
    double cost;
    double flow;
    struct dgraph_edge *next;
} DGEdge, *TDGEdge;

typedef struct dgraph {
    int V, E;
    TDGEdge *out_edges;
    TDGEdge *in_edges;
} DGraph, *TDGraph;

void make_and_add_edges(TDGraph graph, int v1, int v2, double cost)
{
    TDGEdge edge_out = (TDGEdge) calloc(1, sizeof(*edge_out));

    edge_out->id = v2;
    edge_out->cost = cost;
    edge_out->flow = 0;

    edge_out->next = graph->out_edges[v1];
    graph->out_edges[v1] = edge_out;

    return;
}

void make_res_graph_edges(TDGraph graph, TDGraph res_graph)
{
    for (int i = 0; i < graph->V; i++) {
        TDGEdge iter = graph->out_edges[i];
        while (iter != NULL) {
            make_and_add_edges(res_graph, i, iter->id, iter->cost - iter->flow);
            make_and_add_edges(res_graph, iter->id, i, iter->flow);

            iter = iter->next;
        }
    }

    return;
}

int make_level_graph_edges(TDGraph res_graph, TDGraph level_graph)
{
    int V = res_graph->V;
    int *levels = (int *) calloc(V, sizeof(int));
    int *visited = (int *) calloc(V, sizeof(int));

    TQueue queue = (TQueue) malloc(sizeof(*queue));
    queue->head = queue->tail = NULL;

    enqueue(queue, 0);

    int current_vertex;

    while (queue->head != NULL) {
        current_vertex = dequeue(queue);
        TDGEdge iter = res_graph->out_edges[current_vertex];
        while (iter != NULL) {
            if ((levels[iter->id] != 0 && iter->id != V - 1 && levels[iter->id] <= levels[current_vertex]) ||
                    iter->cost <= 1e-9 || iter->id == 0) {
                iter = iter->next;
                continue;
            }

            make_and_add_edges(level_graph, current_vertex, iter->id, iter->cost);
            TDGEdge edge_in = (TDGEdge) calloc(1, sizeof(*edge_in));

            edge_in->id = current_vertex;
            edge_in->cost = iter->cost;
            edge_in->flow = 0;

            edge_in->next = level_graph->in_edges[iter->id];
            level_graph->in_edges[iter->id] = edge_in;
            
            levels[iter->id] = levels[current_vertex] + 1;
            if (visited[iter->id] == 0) {
                enqueue(queue, iter->id);
            }
            visited[iter->id] = 1;

            iter = iter->next;
        }
    }

    if (levels[V - 1] == 0) {
        return 0;
    }

    return 1;
}

void remove_out_edge_graph(TDGraph graph, int v1, int v2)
{
    TDGEdge iter = graph->out_edges[v1];
    TDGEdge parent = NULL;
    while (iter != NULL) {
        if (iter->id == v2) {
            if (parent == NULL) {
                graph->out_edges[v1] = iter->next;
            } else {
                parent->next = iter->next;
            }
            free(iter);

            return;
        }

        parent = iter;
        iter = iter->next;
    }

    return;
}

void remove_in_edge_graph(TDGraph graph, int v1, int v2)
{
    TDGEdge iter = graph->in_edges[v2];
    TDGEdge parent = NULL;
    while (iter != NULL) {
        if (iter->id == v2) {
            if (parent == NULL) {
                graph->in_edges[v2] = iter->next;
            } else {
                parent->next = iter->next;
            }
            free(iter);

            return;
        }

        parent = iter;
        iter = iter->next;
    }

    return;
}

void update_flow(TDGraph graph, int v1, int v2, double flow)
{
    TDGEdge iter = graph->out_edges[v1];
    while (iter != NULL) {
        if (iter->id == v2) {
            iter->flow += flow;
            return;
        }

        iter = iter->next;
    }

    iter = graph->out_edges[v2];

    while (iter != NULL) {
        if (iter->id == v1) {
            iter->flow -= flow;
            return;
        }

        iter = iter->next;
    }

    return;
}

void update_cost_level_graph(TDGraph graph, int v1, int v2, double cost)
{
    TDGEdge iter = graph->out_edges[v1];
    while (iter != NULL) {
        if (iter->id == v2) {
            iter->cost -= cost;
            return;
        }

        iter = iter->next;
    }

    return;
}

void update_res(TDGraph res_graph, int v1, int v2, double flow)
{
    TDGEdge iter = res_graph->out_edges[v1];
    while (iter != NULL) {
        if (iter->id == v2) {
            iter->cost -= flow;
            break;
        }

        iter = iter->next;
    }

    iter = res_graph->out_edges[v2];

    while (iter != NULL) {
        if (iter->id == v1) {
            iter->cost += flow;
            return;
        }

        iter = iter->next;
    }
}

void update_both(TDGraph graph, TDGraph res_graph, int v1, int v2, double res_cap)
{
    TDGEdge iter = graph->out_edges[v1];
    double capacity;
    while (iter != NULL) {
        if (iter->id == v2) {
            capacity = iter->cost;
            iter->flow = iter->cost - res_cap;
        }

        iter = iter->next;
    }
    iter = graph->out_edges[v2];
    while (iter != NULL) {
        if (iter->id == v1) {
            capacity = iter->cost;
            iter->flow = res_cap;
        }

        iter = iter->next;
    }

    iter = res_graph->out_edges[v1];
    while (iter != NULL) {
        if (iter->id == v2) {
            iter->cost = res_cap;
        }

        iter = iter->next;
    }
    iter = res_graph->out_edges[v2];
    while (iter != NULL) {
        if (iter->id == v1) {
            iter->cost = capacity - res_cap;
        }

        iter = iter->next;
    }

    return;
}

void dfs_until_bf_and_modify_graphs(TDGraph graph, TDGraph res_graph, TDGraph level_graph, TDTree forest)
{
    int V = level_graph->V;
    while (1) {
        BBTree_Node *v = root(forest->vertices[0]);
        if (v->value == V - 1) {
            v = mincost(forest->vertices[0]);
            double c = cost(v);
            update(forest->vertices[0], -c);
            while (cost(v) == 0) {
                BBTree_Node *w = parent(v);
                update_res(res_graph, v->value, w->value, c);
                update_flow(graph, v->value, w->value, c);
                remove_out_edge_graph(level_graph, v->value, w->value);
                remove_in_edge_graph(level_graph, v->value, w->value);

                cut(v);

                if (parent(forest->vertices[0]) == NULL) {
                    break;
                }
                v = mincost(forest->vertices[0]);
            }
        } else {
            if (level_graph->out_edges[v->value] == NULL) {
                if (v == forest->vertices[0]) {
                    return;
                } else {
                    TDGEdge iter = level_graph->in_edges[v->value];
                    while (iter != NULL) {
                        double c;
                        TDGEdge aux = iter->next;
                        remove_out_edge_graph(level_graph, iter->id, v->value);
                        BBTree_Node *w = parent(forest->vertices[iter->id]);
                        c = cost(forest->vertices[iter->id]);
                        update_both(graph, res_graph, iter->id, v->value, c);
                        if (w == v) {
                            cut(forest->vertices[iter->id]);
                        }

                        remove_in_edge_graph(level_graph, iter->id, v->value);
                        iter = aux;
                    }
                }
            } else {
                link(v, forest->vertices[level_graph->out_edges[v->value]->id], level_graph->out_edges[v->value]->cost);
            }
        }
    }
}

void free_graph(TDGraph graph)
{
    int V = graph->V;
    for (int i = 0; i < V; i++) {
        TDGEdge iter = graph->out_edges[i];
        TDGEdge aux;
        while (iter != NULL) {
            aux = iter->next;
            free(iter);
            iter = aux;
        }
        while (iter != NULL) {
            aux = iter->next;
            free(iter);
            iter = aux;
        }
    }
    free(graph->out_edges);
    free(graph->in_edges);
    free(graph);

    return;
}

void free_edges(TDGraph level_graph)
{
    int V = level_graph->V;
    for (int i = 0; i < V; i++) {
        TDGEdge iter = level_graph->out_edges[i];
        TDGEdge aux;
        while (iter != NULL) {
            aux = iter->next;
            free(iter);
            iter = aux;
        }
        iter = level_graph->in_edges[i];
        while (iter != NULL) {
            aux = iter->next;
            free(iter);
            iter = aux;
        }
    }
    for (int i = 0; i < V; i++) {
        level_graph->out_edges[i] = NULL;
        level_graph->in_edges[i] = NULL;
    }

    return;
}

double dinic_max_flow(TDGraph graph)
{
    TDGraph res_graph = (TDGraph) malloc(sizeof(*res_graph));
    res_graph->V = graph->V;
    res_graph->E = 2 * graph->E;
    res_graph->out_edges = (TDGEdge *) calloc(res_graph->V, sizeof(TDGEdge));
   
    make_res_graph_edges(graph, res_graph);

    TDGraph level_graph = (TDGraph) malloc(sizeof(*level_graph));
    level_graph->V = graph->V;
    level_graph->out_edges = (TDGEdge *) calloc(res_graph->V, sizeof(TDGEdge));
    level_graph->in_edges = (TDGEdge *) calloc(res_graph->V, sizeof(TDGEdge));
    level_graph->E = 0;

    TDTree forest = init_trees(graph->V);

    int there_is_path = make_level_graph_edges(res_graph, level_graph);
    while (there_is_path == 1) {
        dfs_until_bf_and_modify_graphs(graph, res_graph, level_graph, forest);
        for (int i = 0; i < graph->V; i++) {
            free_path_without_leaves(forest->vertices[i]);
            forest->vertices[i]->dparent = NULL;
        }
        
        free_edges(level_graph);
        there_is_path = make_level_graph_edges(res_graph, level_graph);
    }

    double flow = 0;
    TDGEdge iter = graph->out_edges[0];
    while (iter != NULL) {
        flow += iter->flow;
        iter = iter->next;
    }

    free_graph(res_graph);

    return flow;
}

int main( int argc, const char* args[] )
{
    TDGraph graph = (TDGraph) malloc(sizeof(*graph));
    
    fscanf(INP_FILE, "%d%d", &graph->V, &graph->E);
    graph->out_edges = (TDGEdge *) calloc(graph->V, sizeof(TDGEdge));

    int v1, v2;
    double cost;
    for (int i = 0; i < graph->E; i++) {
        fscanf(INP_FILE, "%d%d%lf", &v1, &v2, &cost);
        v1--;
        v2--;
        if (v2 == 0 || v1 == graph->V - 1) {
            printf("Vertex giving to source or taking from sink.\n");
            return 1;
        }
        make_and_add_edges(graph, v1, v2, cost);
    }
    double max_flow = dinic_max_flow(graph);
    fprintf(OUT_FILE, "%d\n", max_flow);
    free_graph(graph);

    return 0;
}