avatar
fireworks99
keep hungry keep foolish

POJ 2516 Minimum Cost(最小费用最大流)

Description

N个买家,M个卖家,K种货物

接下来N行,每行K个数值,表示每个买家对于K种货物的需求

接下来M行,每行K个数值,表示每个卖家对于K种货物的拥有量

接下来K个矩阵,每个矩阵代表那种货物的有关运输费用

(第k个矩阵第i行第j列的数值,表示第j个卖家运输单位第k种货物到第i个买家的费用)

题目链接:http://poj.org/problem?id=2516 (题目老是AC不了怎么办->去Discuss区看看,我就是不知怎么WA的,去讨论区看,说数组开小了给WA,我开大一些还真AC了,什么鬼……)

Analyze

K种货物分别分析

多源点多汇点->建立超级源点与超级汇点

连接超源到各卖家的路,费用0,容量等于卖家货物量

连接超汇到各买家的路,费用0,容量等于买家需求量

连接卖家与买家间的路,费用对应题目中的费用,容量INF

在可行的前提下,最小费用最大流,原来是最小费用固定流,因为买家到超汇的容量被设为需求量,所以直接求最大流即为该固定流

Code

#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int N = 305;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> P;
typedef long long ll;

void Debug(char * s)
{
    cout << "-------------  " << s << "  -------------" << '\n';
}

int A, B, C;
int n, m;

struct edge
{
    int to, w, cap, rev;
};
vector<edge> vec[N];
int h[N], dis[N];
int fro_v[N], fro_e[N];
int t[105][105], s[105][105], cost[55][305][305];
int tt[105], ss[105];

void add(int from, int to, int w, int cap)
{
    int from_sz = vec[from].size(), to_sz = vec[to].size();
    vec[from].push_back( (edge)
    {
        to, w, cap, to_sz
    } );
    vec[to].push_back( (edge)
    {
        from, -w, 0, from_sz
    } );
}

int min_cost_flow(int s, int t)
{
    int flow = 0;
    ll res = 0;
    memset(h, 0, sizeof(h));
    memset(fro_v, 0, sizeof(fro_v));
    memset(fro_e, 0, sizeof(fro_e));
    while(1)
    {
        priority_queue<P, vector<P>, greater<P> > q;
        memset(dis, INF, sizeof(dis));
        dis[s] = 0;
        q.push(P(0, s));
        while(!q.empty())
        {
            P now = q.top();
            q.pop();
            int to = now.second;
            if(dis[to] > now.first)
                continue;
            for(int i = 0; i < vec[to].size(); ++i)
            {
                edge & nxt = vec[to][i];
                if(nxt.cap > 0 && dis[nxt.to] > dis[to] + nxt.w + h[to] - h[nxt.to])
                {
                    dis[nxt.to] = dis[to] + nxt.w + h[to] - h[nxt.to];
                    fro_v[nxt.to] = to;
                    fro_e[nxt.to] = i;
                    q.push(P(dis[nxt.to], nxt.to));
                }
            }
        }
        if(dis[t] == INF)
            return res;
        for(int v = 0; v <= n; ++v)
            h[v] += dis[v];

        int d = INF;
        for(int v = t; v != s; v = fro_v[v])
            d = min(d, vec[fro_v[v] ][ fro_e[v] ].cap);

        flow += d;
        res += d * h[t];
        for(int v = t; v != s; v = fro_v[v])
        {
            edge & nxt = vec[ fro_v[v] ][ fro_e[v] ];
            nxt.cap -= d;
            vec[v][nxt.rev].cap += d;
        }
    }
    return res;
}


int main()
{
    while(~scanf("%d%d%d", &A, &B, &C))
    {
        n = A + B + 1;
        ll ans = 0;
        if(A == 0 && B == 0 && C == 0)
            break;
        memset(tt, 0, sizeof(tt));
        memset(ss, 0, sizeof(ss));
        memset(s, 0, sizeof(s));
        memset(t, 0, sizeof(t));
        memset(cost, 0, sizeof(cost));

        ///循环赋值时,变量出现顺序 必须跟 欲赋值矩阵维度先后对应
        for(int i = 1; i <= A; ++i)
            for(int j = 1; j <= C; ++j)
                scanf("%d", &t[B + i][j]), tt[j] += t[B + i][j];

        for(int i = 1; i <= B; ++i)
            for(int j = 1; j <= C; ++j)
                scanf("%d", &s[i][j]), ss[j] += s[i][j];

        for(int k = 1; k <= C; ++k)
            for(int i = 1; i <= A; ++i)
                for(int j = 1; j <= B; ++j)
                    scanf("%d", &cost[k][B + i][j]);

        bool flag = 1;
        for(int k = 1; k <= C; ++k)
            if(tt[k] > ss[k])
            {
                flag = 0;
                puts("-1");
                break;
            }
        if(!flag)
            continue;

        for(int i = 1; i <= C; ++i)
        {
            for(int j = 0; j < N; ++j)
                vec[j].clear();
            for(int j = 1; j <= B; ++j)
                add(0, j, 0, s[j][i]);
            for(int j = 1; j <= A; ++j)
                add(B + j, B + A + 1, 0, t[B + j][i]);
            for(int j = 1; j <= B; ++j)
                for(int l = 1; l <= A; ++l)
                    add(j, B + l, cost[i][B + l][j], INF);
            int tem =  min_cost_flow(0, B + A + 1);
            ans += tem;
        }
        cout << ans << '\n';
    }
    return 0;
}
Site by Baole Zhao | Powered by Hexo | theme PreciousJoy