kuangbin專題專題十一 網絡流 Minimum Cost POJ - 2516

題目連接:https://vjudge.net/problem/POJ-2516node

思路:對於每種商品跑最小費用最大流,若是全部商品和人一塊兒建圖跑,O(v^2*m)數量級太大,會超時。ios

把店裏的商品拆點,入和出之間是商品庫存量,起到限流做用。ui

源點->人對該商品的需求->庫存點入->庫存點出->匯點spa

源點與人之間的邊的流爲人的需求量,人對商品之間的邊的流INF。.net

源點與人的邊設置費用,其餘邊費用0.code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

const int N = 60,INF = (int)1e9;
int n,m,k,tot;
int head[N<<2],pre[N<<2],d[N<<2],vis[N<<2];
int p[N][N],g[N][N],c[N][N][N];
struct node{
    int to,nxt,cap,flow,cost;
}e[N*N];

inline void add(int u,int v,int cap,int flow,int cost){
    e[tot].to = v; e[tot].cap = cap; e[tot].flow = flow;
    e[tot].cost = cost; e[tot].nxt = head[u]; head[u] = tot++;

    e[tot].to = u; e[tot].cap = 0; e[tot].flow = flow;
    e[tot].cost = -cost; e[tot].nxt = head[v]; head[v] = tot++;
}

void input(int& sum_need){
    sum_need = 0;
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= k; ++j){
            scanf("%d",&p[i][j]);
            sum_need += p[i][j];
        }
    }
    for(int i = 1; i <= m; ++i){
        for(int j = 1; j <= k; ++j)
            scanf("%d",&g[i][j]);
    }
    for(int o = 1; o <= k; ++o){
        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= m; ++j)
                scanf("%d",&c[o][i][j]);
        }
    }
}

void build_map(int o,int s,int t){
    //0源點   1~n人  n+1~n+m 庫存點入,  
    //n+m+1~n+2*m庫存點出  n+2*m+1匯點。
    for(int i = 1; i <= n; ++i){
        for(int j = 1; j <= m; ++j){
            add(i,j+n,INF,0,c[o][i][j]);
        }
    }
    for(int i = 1; i <= n; ++i){
        add(s,i,p[i][o],0,0);
    }
    for(int i = 1; i <= m; ++i){
        add(i+n,i+n+m,g[i][o],0,0);
        add(i+n+m,t,INF,0,0);
    }
}

bool spfa(int s,int t){
    for(int i = s; i <= t; ++i){
        d[i] = INF; pre[i] = -1; vis[i] = false;
    }
    queue<int > que;
    que.push(s); d[s] = 0; vis[s] = true;
    while(!que.empty()){
        int now = que.front(); que.pop();
        vis[now] = false;
        for(int o = head[now]; ~o; o = e[o].nxt){
            int to = e[o].to;
            if(e[o].cap > e[o].flow && d[to] > d[now] + e[o].cost){
                d[to] = d[now] + e[o].cost;
                pre[to] = o;
                if(!vis[to]){
                    vis[to] = true;
                    que.push(to);
                }
            }
        }
    }
    if(pre[t] == -1) return false;
    else return true;
}

int mcmf(int s,int t,int& mf){

    int Min = INF,mc = 0;
    while(spfa(s,t)){
        Min = INF;
        for(int o = pre[t]; ~o; o = pre[e[o^1].to]){
            Min = min(Min,e[o].cap - e[o].flow);
        }
        for(int o = pre[t]; ~o; o = pre[e[o^1].to]){
            e[o].flow += Min;
            e[o^1].flow -= Min;
        }
        mf += Min;
        mc += d[t]*Min;
    }
    return mc;
}

void init_main(){
    memset(p,0,sizeof(p));
    memset(g,0,sizeof(g));
    memset(c,0,sizeof(c));
}

int main(){

    int s,t,mc,mf,sum_need;//商品總需求量
    while(~scanf("%d%d%d",&n,&m,&k) && (n+m+k)){
        init_main();
        input(sum_need);
        s = 0; t = n + 2*m + 1;
        mc = mf = 0;
        for(int o = 1; o <= k; ++o){//第o種商品
            for(int i = s; i <= t; ++i) head[i] = -1; tot = 0;
            build_map(o,s,t);
            mc += mcmf(s,t,mf);
        }
        //if(mf == sum_need) printf("-------------%d\n",mc);
        //else printf("--------------no\n");
        if(mf == sum_need) printf("%d\n",mc);
        else printf("-1\n");
    }

    return 0;
}
相關文章
相關標籤/搜索