Loj#6011. 运输问题 (最最基础费用流模板题)

15 篇文章 0 订阅


题目描述

W 公司有 m mm 个仓库和 n nn 个零售商店。第 i ii 个仓库有 ai a_iai 个单位的货物;第 j jj 个零售商店需要 bj b_jbj 个单位的货物。货物供需平衡,即 ∑i=1mai=∑j=1nbj \sum\limits_{i = 1} ^ m a_i = \sum\limits_{j = 1} ^ n b_ji=1mai=j=1nbj。从第 i ii 个仓库运送每单位货物到第 j jj 个零售商店的费用为 cij c_{ij}cij。试设计一个将仓库中所有货物运送到零售商店的运输方案,使总运输费用最少。

输入格式

第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示仓库数和零售商店数。接下来的一行中有 m mm 个正整数 ai a_iai,表示第 i ii 个仓库有 ai a_iai 个单位的货物。再接下来的一行中有 n nn 个正整数 bj b_jbj,表示第 j jj 个零售商店需要 bj b_jbj 个单位的货物。接下来的 m mm 行,每行有 n nn 个整数,表示从第 i ii 个仓库运送每单位货物到第 j jj 个零售商店的费用 cij c_{ij}cij

输出格式

两行分别输出最小运输费用和最大运输费用。

样例
样例输入
2 3
220 280
170 120 210
77 39 105
150 186 122
样例输出
48500
69140
数据范围与提示

1≤n,m≤100 1 \leq n, m \leq 1001n,m100

输出最小费用最大费用, 最大费用就是费用反向建图就好了

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 1e2 + 7;
const int maxe = 200005;
const int INF = 0x3f3f3f3f;
int head[maxe], dis[maxn], path[maxn], pre[maxn], book[maxn] , n, m, s, t, k, sum;
int a[maxn], b[maxn], c[maxn][maxn];
struct node
{
    int v, w, f, next, cnt;
}edge[maxe];
void addEdge(int u, int v, int f, int w)
{
    edge[k].v = v;
    edge[k].w = w;
    edge[k].f = f;
    edge[k].cnt = k;
    edge[k].next = head[u];
    head[u] = k++;
    edge[k].v = u;
    edge[k].w = -w;
    edge[k].f = 0;
    edge[k].cnt = k;
    edge[k].next = head[v];
    head[v] = k++;
}
void init()
{
    s = 0, t = n+m+1, k = 0;
    memset(head, -1, sizeof(head));
}
int spfa()
{
    queue<int> q;
    q.push(s);
    memset(pre, -1, sizeof(pre));
    memset(path, -1, sizeof(path));
    for(int i = 1; i <= t; i++) dis[i] = INF;
    dis[s] = 0;
    memset(book, 0, sizeof(book));
    book[s] = 1;
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        book[u] = 0;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int to = edge[i].v;
            int w = edge[i].w;
            int f = edge[i].f;
            if(f && dis[to] > dis[u] + w)
            {
                dis[to] = dis[u] + w;
                pre[to] = u;
                path[to] = edge[i].cnt;
                if(!book[to])
                {
                    q.push(to);
                    book[to] = 1;
                }
            }
        }
    }
    if(dis[t] != INF) return 1;
    else return 0;
}
int Min_costflow()
{
    int ans = 0;
    int maxflow = 0;
    while(spfa())
    {
        int minx = INF;
        for(int i = t; i != s; i = pre[i])
        {
            minx = min(minx, edge[path[i]].f);
        }
        maxflow += minx;
        ans += dis[t]*minx;
        for(int i = t; i != s; i = pre[i])
        {
            edge[path[i]].f -= minx;
            edge[path[i]^1].f += minx;
        }
    }
    return ans;
}
int main()
{
    while(~scanf("%d%d", &m, &n))
    {
        init();
        int x, y, z;
        for(int i = 1; i <= m; i++)
        {
            scanf("%d", &a[i]);
            addEdge(s, i, a[i], 0);
        }
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &b[i]);
            addEdge(i+m, t, b[i], 0);
        }
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= n; j++)
            {
                scanf("%d", &c[i][j]);
                addEdge(i, j+m, a[i], c[i][j]);
            }
        printf("%d\n", Min_costflow());
        init();
        for(int i = 1; i <= m; i++)
            addEdge(s, i, a[i], 0);
        for(int i = 1; i <= n; i++)
            addEdge(i+m, t, b[i], 0);
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= n; j++)
                addEdge(i, j+m, a[i], -c[i][j]);
        printf("%d\n", -Min_costflow());
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值