Dinic算法 (优化)

Dinic 算法(优化)

前言: (个人而言)
  1. dfs_test()我以前学然后写Dinic中的dfs用来增广

  2. 新的dfs()速度比原来快很多

    1. 判断 向下增广返回的流是否为0

    2. 返回的流不为0代表增广成功 维护边后直接回溯

    3. 原来的dfs_test处于一个点时 : 只要所有出边遍历结束才回溯,


优化

  1. 当前弧优化 :
  1. 原来的dfs都是从每个点的第一条边开始遍历,导致已经增广过的边会被重复dfs
  2. 开一个cur[]记录每一个点当前增广到的边,当其他的dfs增广到的时候,从有效的边开始增广,
  • bfs分层后初始化cur[], 即head[]每个点的第一条边,
  1. 分层优化(说法不一,其他blog学习到的,下同): bfs分层时找到汇点直接退出
  2. 剩余量优化: 用不到我新学的dfs上, 但是原来的dfs_test可以优化

需要Dinic优化才能过 且 建图巧妙 luogu P1361 最小割

  1. 源点 s ∈ S s \in S sS,源点和每个点连边代表在 S S S部分的收益, 同理汇点 t ∈ T t \in T tT,每个点和汇点连边代表处于 T T T部分的收益

  2. 建虚点 处理部分点所在的点集处于图的2个部分的额外收益

    1. 点集看做2个点,在 S S S部分时, 源点向虚点 连边且边权代表额外收益,
    2. 如何处理,点集中任意一个点不在此集合中会额外收益也消失
    3. 虚点连向点集中每个点一条边权为无穷的边,
    4. 当点集中的点被割到另一集合中时,这条inf的边使得源点和虚点的边(额外收益)的边也被割掉
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3010;
const int maxm = 2e6+5;
const int inf  = 0x3f3f3f3f;
struct Edge {
    int v,c,next;
} edge[maxm];

int n,m,tot,source,sink,cnt;
int head[maxn],dep[maxn],cur[maxn];

void add(int u,int v,int c) {
    edge[tot].v=v; edge[tot].c=c;
    edge[tot].next=head[u]; head[u]=tot++;
}
void addedge(int u,int v,int c) {
    add(u,v,c);
    add(v,u,0);
}

bool bfs() {
    queue<int> que;
    memset(dep,-1,sizeof dep);
    dep[source] = 0;
    que.push(source);
    while (!que.empty()) {
        int u = que.front(); que.pop();
        for (int i=head[u]; i!=-1; i=edge[i].next) {
            int to = edge[i].v;
            if (edge[i].c>0 && dep[to] == -1) {
                dep[to] = dep[u] + 1;
                que.push(to);
                // 找到汇点直接退出 优化2
                if (to == sink) return 1;
            }
        }
    }
    return dep[sink] != -1;
}

int dfs(int u,int dist) {
    if (u == sink)
        return dist;
    for (int &i=cur[u]; i!=-1; i=edge[i].next) { // 通过引用更新cur[]:记录每个点当前增广的边
        int to = edge[i].v;
        if (edge[i].c>0 && dep[to]==dep[u]+1) {
            int temp = dfs(to,min(dist,edge[i].c));
            if (temp > 0) {
                edge[i].c -= temp;
                edge[i^1].c += temp;
                return temp;
            }
        }
    }
    return 0;
}

int dfs_test(int u,int delta) {
    if (u == sink)
        return delta;
    int flow = 0;
    for (int &i=cur[u]; i!=-1; i=edge[i].next) {
        int to = edge[i].v;
        if (edge[i].c>0 && dep[to]==dep[u]+1) {
            int temp = dfs(to,min(delta-flow,edge[i].c));
            edge[i].c   -= temp;
            edge[i^1].c += temp;
            flow += temp;
            // 没有流量就打破循环 优化3
            if (delta-flow <= 0) break;
        }
    }
    if (!flow) dep[u] = -1;
    return flow;
}

int Dinic() {
    int ans = 0;
    while (bfs()) { 
        for (int i=0; i<cnt; ++i) // 分层后每个点当前增广到的边当然是第一条边
            cur[i] = head[i];
        while(1) {
            int temp = dfs(source,inf);
            //int temp = dfs_test(source,inf);
            if (!temp) break;
            ans += temp;
        }
    }
    return ans;
}

int main() {
    memset(head,-1,sizeof head);
    scanf("%d",&n);
    source = 0;
    sink = n+1;
    int tot_val = 0;
    for (int i=1; i<=2*n; ++i) {
        int val; scanf("%d",&val);
        tot_val += val;
        if (i <= n) {
            addedge(source,i,val);
        } else {
            addedge(i-n,sink,val);
        }
    }
    scanf("%d",&m);
    cnt = sink+1;
    for (int i=1; i<=m; ++i) {
        int k,c1,c2,to;
        //cin >> k >> c1 >> c2;
        scanf("%d%d%d",&k,&c1,&c2);
        tot_val += (c1+c2);
        addedge(source,cnt++,c1);
        addedge(cnt++, sink, c2);
        while (k--) {
            //cin >> to;
            scanf("%d",&to);
            addedge(cnt-2,to,inf);
            addedge(to,cnt-1,inf);
        }
    }
    int maxflow = Dinic();
    //cout << tot_val-maxflow << endl;
    printf("%d\n",tot_val - maxflow);
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用C++实现的Fold-Fulkerson算法和Dinic算法: ```cpp #include <bits/stdc++.h> using namespace std; struct Edge { int from, to, cap, flow; }; const int MAXN = 1005; const int INF = 0x3f3f3f3f; vector<Edge> edges; vector<int> G[MAXN]; int d[MAXN], cur[MAXN]; int n, m, s, t; void addEdge(int from, int to, int cap) { edges.push_back((Edge){from, to, cap, 0}); edges.push_back((Edge){to, from, 0, 0}); int m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } bool bfs() { memset(d, -1, sizeof(d)); queue<int> q; q.push(s); d[s] = 0; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = 0; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (d[e.to] == -1 && e.cap > e.flow) { d[e.to] = d[u] + 1; q.push(e.to); } } } return d[t] != -1; } int dfs(int u, int a) { if (u == t || a == 0) return a; int flow = 0, f; for (int &i = cur[u]; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (d[u] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) { e.flow += f; edges[G[u][i] ^ 1].flow -= f; flow += f; a -= f; if (a == 0) break; } } return flow; } int dinic() { int flow = 0; while (bfs()) { memset(cur, 0, sizeof(cur)); flow += dfs(s, INF); } return flow; } int maxflow() { int flow = 0; while (bfs()) { memset(cur, 0, sizeof(cur)); flow += dfs(s, INF); } return flow; } int dfs_fold_fulkerson(int u, int t, int f) { if (u == t) return f; int flow = 0; for (int i = 0; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (e.cap > e.flow && d[e.to] == d[u] + 1) { int g = dfs_fold_fulkerson(e.to, t, min(f, e.cap - e.flow)); if (g == 0) d[e.to] = -1; e.flow += g; edges[G[u][i] ^ 1].flow -= g; flow += g; f -= g; if (f == 0) break; } } return flow; } int fold_fulkerson() { int flow = 0; while (true) { memset(d, -1, sizeof(d)); queue<int> q; q.push(s); d[s] = 0; if (!bfs()) break; while (!q.empty()) { int u = q.front(); q.pop(); for (int i = 0; i < G[u].size(); i++) { Edge &e = edges[G[u][i]]; if (d[e.to] == -1 && e.cap > e.flow) { d[e.to] = d[u] + 1; q.push(e.to); } } } flow += dfs_fold_fulkerson(s, t, INF); } return flow; } int main() { cin >> n >> m >> s >> t; for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; addEdge(u, v, w); } cout << "Max flow: " << maxflow() << endl; cout << "Fold-Fulkerson max flow: " << fold_fulkerson() << endl; return 0; } ``` 该代码首先读入节点数、边数、源点和汇点,然后使用 `addEdge` 函数将每条带权边添加到图中。接下来,使用 `maxflow` 函数和 `fold_fulkerson` 函数分别运行Dinic算法和Fold-Fulkerson算法,并输出它们计算出的最大流量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值