求助dinic是否写假

P3376 【模板】网络最大流

altgo @ 2022-01-25 15:33:01

已经过题,但是时间比其他选手的劣很多。

希望能帮忙看一下,谢谢。

参考提交(别人的,总共59ms):https://www.luogu.com.cn/record/67846830

我的代码(总共279ms):

#include <bits/stdc++.h>
using namespace std;

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define go(i,a) for(int i=cur[a];i;i=edge[i].nxt)
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long

const int N = 5005;
const int INF = 2e9;

int n, m;
struct nod {
    int y, nxt;
    int c;
}edge[N<<2];
int el = 1;
int Edgehead[N];
int dis[205];
int cur[205];
int S, T;
int q[205], head, tail;

void add (int x, int y, ll c) {
    el++;
    edge[el].y = y, edge[el].c = c, edge[el].nxt = Edgehead[x], Edgehead[x] = el;
    return;
}

void ins (int x, int y, ll c) {
    add (x, y, c);
    add (y, x, 0ll);
    return;
}

bool bfs () {
    mem (dis, -1);
    dis[S] = 0;
    q[head = 1] = S, tail = 2;
    while (head < tail) {
        int x = q[head++];
        cur[x] = 0;
        for (int i = Edgehead[x]; i; i = edge[i].nxt) {
            int y = edge[i].y;
            if (edge[i].c && dis[y] == -1) {
                if (!cur[x]) cur[x] = i;
                dis[y] = dis[x] + 1;
                q[tail++] = y;
            }
        }
    }
    return dis[T] != -1;
}

int dfs (int k, int flow) {
    if (k==T || !flow) return flow;
    int have = 0;
    go (i,k) {
        int y=edge[i].y;
        if (dis[y] == dis[k]+1 && edge[i].c) {
            int back = dfs (y, min(flow-have, edge[i].c));
            have += back;
            edge[i].c -= back;
            edge[i^1].c += back;
            if (have == flow)return flow;
        }
        cur[k] = edge[i].nxt;
    }
    dis[k] = -1;
    return have;
}

int main () {
//  freopen ("3376.in", "r", stdin);
    mem (Edgehead, 0);
    scanf ("%d %d %d %d", &n, &m, &S, &T);
    fo (i,1,m) {
        int x, y, c;
        scanf ("%d %d %d", &x, &y, &c);
        ins (x, y, c);
    }
    ll ans = 0;
    while (bfs ()) {
        ans += dfs (S, INF);
    }
    printf ("%lld\n", ans);
    return 0;
}

by Computer1828 @ 2022-01-25 15:52:01

@altgo 你把 bfs 中改成这样既可:

bool bfs () {
    for(int i = 0;i<=n+1;++i) dis[i] = -1,cur[i] = Edgehead[i];
    dis[S] = 0;
    q[head = 1] = S, tail = 2;
    while (head < tail) {
        int x = q[head++];
        for (int i = Edgehead[x]; i; i = edge[i].nxt) {
            int y = edge[i].y;
            if (edge[i].c && dis[y] == -1) {
                dis[y] = dis[x] + 1;
                q[tail++] = y;
                if(y == T) return true;
            }
        }
    }
    return false;
}

by altgo @ 2022-01-25 16:03:29

@Fmyh1828 感谢大佬!关注了。

不过为什么呢?

理论上流量为 0 的边就算在 DFS 过程中被遍历到也会直接被跳过。

为什么每次一定要将 cur[] 赋为第一条边呢?


by Computer1828 @ 2022-01-25 16:08:55

@altgo 我认为关键应该是只要找到一条增光路就可以进行dfs了,就不用一定要跑完全图。


by altgo @ 2022-01-25 16:13:57

@Fmyh1828 事实上,我的代码也是实现了这一点啊;并且,经过比较,我发现真正改善复杂度的关键在于将循环内对于 cur[x]=i 的赋值改到了外面首先 cur[x]=Edgehead[x] ;经过控制变量,发现在这一步上,复杂度实现了极大的优化。

想请教一下您为什么这样就会变得很快呢?


by Computer1828 @ 2022-01-25 16:24:03

@altgo 可能是减少了赋值运算量?


by altgo @ 2022-01-25 16:37:31

@Fmyh1828 这样吗?但是我感觉赋值对于时间复杂度的影响不会很大啊;而且好像也没有减少赋值运算量啊(


by Computer1828 @ 2022-01-25 16:47:48

@altgo 减少是肯定有的,你可以自己试一下。至于为什么会快那么多我也说不清


by altgo @ 2022-01-25 19:30:35

@Fmyh1828 谢谢DL


|