网络流模板--spfa

/*
 *用spfa去求最小费用流,首先是找到最小费用,然后通过最小费用求最大流
 */


struct Edge {
    int start;
    int end;
    int cap;
    int cost;
    int next;
};

struct Edge edge[MAX_EDGE];
int head[MAX_POINT], queue[MAX_POINT], pre_edge[MAX_POINT];



int spfa() {
    int i, cnt_point, next_point, next_edge, front, rear;
    for (i = 0; i <= point_number; i++) {
        distance[i] = INF; 
    }
    memset(vis, 0, sizeof(vis));
    /*入队*/
    vis[source] = 1;
    distance[source] = 0;
    front = 0;
    rear = 1;
    queue[front] = source;
    /*找到最小费用*/
    while (front < rear) {
        cnt_point = queue[front];
        vis[cnt_point] = 1;
        for (next_edge = head[cnt_point]; next_edge != -1; next_edge = edge[next_edge].next) {
            next_point = edge[next_edge].end;
            if (edge[next_edge].cap > 0 && distance[next_point] > distance[cnt_point] + edge[next_edge].cost) {
                distance[next_point] = distance[cnt_point] + edge[next_edge];
                /*记录更新此费用的边号*/                
                pre_edge[next_point] = next_edge;
                if (!vis[next_point]) {
                    queue[rear] = next_point;
                    rear++;
                    rear = rear % QUEUE_LENTH;
                }
            }
        }
        front++;
        front = front % QUEUE_LENTH;
        vis[cnt_point] = 0;
    }
    /*找不到最小费用了*/
    if (distance[destination] == INF) {
        return 0;
    }
    min_flow = INF;
    /*找到最小费用之后找到可以通过的最大流*/
    for (i = destination; i != source; i = edge[pre_edge_number].start) {
        pre_edge_number = pre_edge[i];
        if (min_flow > edge[pre_edge_number].cap) {
            min_flow = edge[pre_edge_number].cap;
        }
    }
    for (i = destination; i != source; i = edge[pre_edge_number].start) {
        pre_edge_number = pre_edge[i];
        edge[pre_edge_number].cap -= min_flow;
        edge[pre_edge_number ^ 1].cap += min_flow;
        costs += edge[pre_edge_number].cost * min_flow;
    }
    flow += min_flow;
    return 1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值