洛谷P3381: 最小费用最大流模板(spfa + dinic)

2020.7.3
费用流模板,终于弄明白了。因为去年写的第一篇就是网络流的模板,所以感觉要弄懂这个其实门槛不算很高,增广路和添加反向边去年第一次听的时候感觉很高端,但是其实不难,去年看不懂一个是因为我太菜,另一个是因为郭神的代码太高端了吧。

学习其实有时候往往不是一个线性的增长,前期投入大量时间和精力却换来了未能出线的结果,后期知识体系完善了学习效率往往能实现飞跃。比如溯祖,去年第一次在Edmond Karp算法里接触到的时候怎么捋不顺,但是学了树链剖分和ac自动机之后这些都是基操,还有链式前向星,我在过去的日记中吐槽过这种静态链表的晦涩难懂,然而图论写多了之后用什么当邻接表只是最不重要的一步了。这些都是知识体系的建立,我很有幸能够接触到这么丰富的知识。

今年看看能不能倒逼学校给我们找个大学就读吧,西安电子科技大,国科大也好,复旦也罢,不管怎么讲一个校园环境对于我们这种适应了学校生活的人来说还是治愈性的,对自己带来的改变,一个校园,就算上网课也无妨。

这个就是用spfa边求费用边求增广路,套上dinic作为最大流的工具,咱也有机会了解了下noi d1t1那么多选手是怎么挂的了hhhh。

代码:

#include <bits/stdc++.h>
using namespace std;
#define limit (100000 + 5)//防止溢出
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f
#define lowbit(i) i&(-i)//一步两步
#define EPS 1e-6
#define FASTIO  ios::sync_with_stdio(false);cin.tie(0);
#define ff(a) printf("%d\n",a );
#define pi(a,b) pair<a,b>
#define rep(i, a, b) for(ll i = a; i <= b ; ++i)
#define per(i, a, b) for(ll i = b ; i >= a ; --i)
#define MOD 988244353
#define FOPEN freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\data.txt", "rt", stdin)
#define FOUT freopen("C:\\Users\\tiany\\CLionProjects\\acm_01\\dabiao.txt", "wt", stdout)
typedef long long ll;
typedef unsigned long long ull;
ll read(){
    ll sign = 1, x = 0;char s = getchar();
    while(s > '9' || s < '0' ){if(s == '-')sign = -1;s = getchar();}
    while(s >= '0' && s <= '9'){x = (x << 3) + (x << 1) + s - '0';s = getchar();}
    return x * sign;
}//快读
void write(ll x){
    if(x < 0) putchar('-'),x = -x;
    if(x / 10) write(x / 10);
    putchar(x % 10 + '0');
}
int n,m,vs,ve;
int head[limit],cnt;
int dist[limit],fa[limit],vis[limit],pre[limit];
struct node{
    int to, next, flow, w;
}edge[limit<<1];
void add(int u, int v, int flow, int w){
    edge[cnt].to = v;
    edge[cnt].flow = flow;
    edge[cnt].w = w;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}
void init(int flag = 0){
    if(flag){
        memset(dist, INF, sizeof(dist));
        memset(vis, 0 , sizeof(vis));
    }else{
        memset(head, -1, sizeof(head));
        cnt = 0;
    }
}
int spfa(){
    queue<int>q;
    init(1);
    dist[vs] = 0;
    vis[vs] = 1;
    q.push(vs);
    pre[ve] = -1;
    while (q.size()){
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; ~i; i = edge[i].next){
            int v = edge[i].to, w = edge[i].w;
            int stream = edge[i].flow;
            if(dist[u] + w < dist[v] && stream > 0){
                dist[v] = dist[u] + w;
                pre[v] = i;
                fa[v] = u;
                if(!vis[v]){
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
    }
    return ~pre[ve];
}

int max_flow,min_cost;
void dinic(){
    while (spfa()){
        int min_flow = INF;
        for(int i = ve; i != vs; i = fa[i]){
            min_flow = min(min_flow, edge[pre[i]].flow);
        }
        max_flow += min_flow;
        min_cost  += dist[ve] * min_flow;
        for(int i = ve; i != vs; i = fa[i]){
            edge[pre[i]].flow -= min_flow;
            edge[pre[i] ^ 1].flow += min_flow;
        }
    }
}
int main() {
#ifdef LOCAL
    FOPEN;
#endif
    n = read(), m = read(), vs= read(), ve =read();
    init();
    rep(i, 1, m){
        int x= read(),y = read(), floww = read() , w = read();
        add(x,y,floww,w);
        add(y,x,0,-w);
    }
    max_flow = min_cost = 0;
    dinic();

    printf("%d %d", max_flow, min_cost);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章