zoukankan      html  css  js  c++  java
  • POJ-2516 Minimum Cost

    题目链接:POJ-2516 Minimum Cost

    题意

    有$n$个商店,$m$个供货商和$k$种物品,首先$n$行$k$列的矩阵第$i$行$j$列的数字表示第$i$个商店对第$j$种物品的需求量,接下来$m$行$k$列的矩阵第$i$行$j$列的数字表示第$i$个供货商对第$j$种物品的储藏量,接下来$k$个$n$行$m$列的矩阵,第$i$个矩阵第$j$行$p$列表示从第$p$个供应商运输1个单位第$i$种物品到第$j$个商店需要的花费。问满足所有商店的物品需求前提下,最小花费是多少,若不能满足需求,输出-1。


    思路

    不难看出这是一道最小费用最大流的题目,可对每个商店和供应商都拆成$k$个点建图,但这样流网络的规模较大,很可能会超时。注意到$k$个物品互相是独立的,我们可以对每个物品跑最小费用流,这样就不用拆点,由于用Dijkstra改进算法求解最小费用最大流的时间复杂度为$O(FElogV)$,流网络规模缩小$k$倍后,$F,E,V$都会缩小$k$倍,虽然$k$个物品要跑$k$次,但显然总的时间复杂度仍然明显减小。建图如下:

    源点向每个供应商连边,容量为供应商对当前物品的储藏量,费用为0;

    每个供应商向每个商店连边,容量为无穷大,费用为当前物品从对应的供应商到对应商店需要的运输单价;

    每个商店向汇点连边,容量为商店对当前物品的需求量,费用为0;


    代码实现 

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <cstdlib>
    #include <cstring>
    #define N 200
    using namespace std;
    typedef pair<int, int> P;
    const int INF = 0x3f3f3f3f;
    struct Edge
    {
        int to, cap, cost, rev;
        Edge(int t, int c, int cc, int r) :to(t), cap(c), cost(cc), rev(r){}
    };
    int V;
    vector<Edge> G[N];
    int h[N];
    int dist[N];
    int prevv[N];
    int preve[N];
    int ned[60][60], sup[60][60], k_tot[60];
    
    void addedge(int from, int to, int cap, int cost)
    {
        G[from].push_back(Edge(to, cap, cost, G[to].size()));
        G[to].push_back(Edge(from, 0, -cost, G[from].size() - 1 ));
    }
    int min_cost_flow(int s, int t, int f)
    {
        int res = 0;
        fill(h, h + V, 0);
        while (f > 0)
        {
            priority_queue<P, vector<P>, greater<P> >q;
            fill(dist, dist + V, INF);
            dist[s] = 0;
            q.push(P(0, s));
            while (!q.empty())
            {
                P p = q.top(); q.pop();
                int v = p.second;
                if (dist[v] < p.first)continue;
                for (int i = 0; i < G[v].size(); i++)
                {
                    Edge &e = G[v][i];
                    if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to])
                    {
                        dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        q.push(P(dist[e.to], e.to));
                    }
                }
            }
            if (dist[t] == INF) return -1;
            for (int j = 0; j < V; j++)
                h[j] += dist[j];
            int d = f;
            for (int x = t; x != s; x = prevv[x])
                d = min(d, G[prevv[x]][preve[x]].cap);
            f -= d;
            res += d * h[t];
            for (int x = t; x != s; x = prevv[x])
            {
                Edge &e = G[prevv[x]][preve[x]];
                e.cap -= d;
                G[x][e.rev].cap += d;
            }
        }
        return res;
    }
    
    int main()
    {
        int n, m, k;
        while (~scanf("%d %d %d", &n, &m, &k) && (n || m || k)) {
            V = n + m + 2;
            memset(k_tot, 0, sizeof(k_tot));
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < k; j++) {
                    scanf("%d", &ned[i][j]);
                    k_tot[j] += ned[i][j];
                }
            }
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < k; j++) {
                    scanf("%d", &sup[i][j]);
                }
            }
            int s = n + m, t = n + m + 1, ans = 0;
            for (int i = 0; i < k; i++) {
                for (int j = 0; j < V; j++) G[j].clear();
                for (int j = 0; j < m; j++) addedge(s, j, sup[j][i], 0);
                for (int j = 0; j < n; j++) addedge(m + j, t, ned[j][i], 0);
                for (int j = 0, cost; j < n; j++) {
                    for (int p = 0; p < m; p++) {
                        scanf("%d", &cost);
                        addedge(p, j + m, INF, cost);
                    }
                }
                if (ans == -1) continue;
                int tmp = min_cost_flow(s, t, k_tot[i]);
                if (tmp == -1) ans = -1;
                else ans += tmp;
            }
            printf("%d
    ", ans);
        }
        return 0;
    }
    View Code
    作者:_kangkang
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    JAVA微信公众号网页开发——获取公众号关注的所有用户
    删除mysl
    sql语言(mysql)
    mycat读写分离
    mysql双主双从技术
    实用的10个日志处理案例
    ansible基本操作
    MySQL改密
    mysql源码包安装
    ftp搭建mysql服务器
  • 原文地址:https://www.cnblogs.com/kangkang-/p/11329128.html
Copyright © 2011-2022 走看看