洛谷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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章