POJ-1459(多源多汇最大流,Dinic算法)

电场可以分为两个节点,节点间的流量上限是电场的最大发电量,用户可以分为两个节点,节点间的流量上限是用户的最大需求,再加上总的虚拟源点和总的虚拟汇点,虚拟源点到源点间的流量上限为INF,汇点到虚拟汇点间的流量上限为INF,接着就是最大流算法了:


#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
#define INF 99999999

int S, T, n, np, nc, m, total;
struct Edge{
    int from, to, capacity, flow;
    Edge(int f, int t, int c) : from(f), to(t), capacity(c), flow(0){}
};
vector<Edge> edges;  //all edges
vector<int> out[202];//edge indexes streching out of each node
bool vis[202];
int  dis[202];
int  cur[202];

bool input()
{
    if(scanf("%d %d %d %d", &n, &np, &nc, &m) != 4) return false;
    total = n + np + nc + 2;
    S = total - 2;
    T = total - 1;
    
    int i, j, from, to, cap;
//initialize
    edges.clear();
    for(i = 0; i < total; ++i) out[i].clear();
//input edges
    for(i = 0; i < m; ++i){
        while(getchar() != '(') ;
        scanf("%d,%d)%d", &from, &to, &cap);
        out[from].push_back(edges.size());
        edges.push_back(Edge(from, to, cap));
    }
//input power stations
    j = n;//index of added nodes
    for(i = 0; i < np; ++i, ++j){
        while(getchar() != '(') ;
        scanf("%d)%d", &to, &cap);
        //divide power station into two nodes with edge been its power capacity
        out[j].push_back(edges.size());
        edges.push_back(Edge(j, to, cap));
        //connect S with power station with edge been INF
        out[S].push_back(edges.size());
        edges.push_back(Edge(S, j, INF));
    }
//input consumers
    for(i = 0; i < nc; ++i, ++j){
        while(getchar() != '(') ;
        scanf("%d)%d", &from, &cap);
        //divide consumer into two nodes with edge been its consuming ability
        out[from].push_back(edges.size());
        edges.push_back(Edge(from, j, cap));
        //connect j with T with edge been INF
        out[j].push_back(edges.size());
        edges.push_back(Edge(j, T, INF));
    }
    return true;
}
bool bfs()
{
//initialize
    memset(vis, false, total);
    queue<int> q;
    q.push(S);
    vis[S] = true;
    dis[S] = 0;
//BFS to find augment path
    while(!q.empty()){
        int from = q.front(); q.pop();
        for(int i = 0, n = out[from].size(); i < n; ++i){
            Edge& e = edges[out[from][i]];
            int to = e.to;
            if(!vis[to] && e.capacity > e.flow){
                vis[to] = true;
                dis[to] = dis[from] + 1;
                q.push(to);
            }
        }
    }
//return flag if has augment path to meeting point
    return vis[T];
}
int dfs(int from, int residual)
{
    if(from == T || residual == 0) return residual;
    
    int flow = 0, f;
    for(int& i = cur[from]; i < out[from].size(); ++i){//这里是一个剪枝,从上次递归的边继续搜索,因为之前的边已经增广过了,不会再次进行增广了
        Edge& e = edges[out[from][i]];
        if(dis[from] + 1 == dis[e.to] && 
           0 < (f = dfs(e.to, min(residual, e.capacity - e.flow)))
           ){
            e.flow += f;
            flow += f;
            residual -= f;
            if(residual == 0) break;//这里也是一个剪枝
        }
    }
    return flow;
}
int maxFlow()
{
    int flow = 0;
    while(bfs()){
        memset(cur, 0, total << 2);
        flow += dfs(S, INF);
    }
    return flow;
}

int main()
{
    while(input()) printf("%d\n", maxFlow());
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值