POJ2516 Minimum Cost

一.原题链接:http://poj.org/problem?id=2516

二.题目大意:Dearboy是销售商,有N个店主帮他卖东西,他有M个生产地,有K种商品,每个生产地的每种商品给每个店主的花费都是不同的,求在满足所有店主的预定下,(不满足输出-1),求最小花费。

三.思路:明显的最小费用最大流问题,真的很明显。刚开始还想把K个商品拆了中间连一条其花费的线,听说会超时,建议不要试。其实可以每种商品求一次最大流,如果其中一种商品不满足店主需求,输出-1,全部满足直接把它们都加起来。

建图如下:(求K次)

1.超级源点S和每个生产地连起来,容量为其产出,花费为0。

2.超级汇点T和每个店主连起来,容量为其需求,花费为0。(每次都需要满流,不然输出-1)

3.生产地和店主之间连对应的花费。

注意事项:

1.它给的是单位容量的花费,所以记得要乘上容量啊,就是说在求花费的时候,在索引路的时候,要顺手把增广的流乘以单位花费啊,就是在这里WA了一次。画图画一边就知道是自己傻逼了。

2.我为什么要使用堆空间呢,因为我想在一个函数里面建图,这样每求一次最大流后它就会自动析构,使用栈空间又怕爆,所以。。

四.代码:

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
#include <cstdlib>

using namespace std;

const int INF = 0x3f3f3f3f,
          MAX_SIZE = 1000;

class AdjList
{
public:
    int *head, cnt;
    struct Edge
    {
        int cost, cap, v, next;
    }*edges;

    AdjList()
    {
        edges = new Edge[MAX_SIZE*MAX_SIZE];
        head = new int[MAX_SIZE];
        cnt = 0;
        memset(head, -1, sizeof(int)*MAX_SIZE);
    }

    ~AdjList()
    {
        delete[] edges;
        delete[] head;
    }
    void addEdge(int u, int v, int cap, int cost)
    {
        edges[cnt].v = v, edges[cnt].cap = cap,
        edges[cnt].cost = cost, edges[cnt].next = head[u];
        head[u] = cnt++;

        edges[cnt].v = u, edges[cnt].cap = 0,
        edges[cnt].cost = -cost, edges[cnt].next = head[v];
        head[v] = cnt++;
    }
};

class MinCost
{
public:
    AdjList G;
    int *dist, *pre, *path, s, t;
    MinCost()
    {
        dist = new int[MAX_SIZE];
        pre  = new int[MAX_SIZE];
        path = new int[MAX_SIZE];
    }

    ~MinCost()
    {
        delete[] dist;
        delete[] pre;
        delete[] path;
    }

    bool SPFA()
    {
        bool inQue[MAX_SIZE];
        queue <int> que;
        int cur, v, i;

        memset(dist, INF, sizeof(int)*MAX_SIZE);
        memset(inQue, 0, sizeof(inQue));
        memset(pre, -1, sizeof(int)*MAX_SIZE);

        dist[s] = 0;
        que.push(s);
        inQue[s] = true;

        while(!que.empty()){
            cur = que.front();
            que.pop();
            inQue[cur] = false;
            for(i = G.head[cur]; i != -1; i = G.edges[i].next){
                v = G.edges[i].v;
                if(G.edges[i].cap && dist[v] > dist[cur] + G.edges[i].cost){
                    dist[v] = dist[cur] + G.edges[i].cost;
                    pre[v] = cur;
                    path[v] = i;
                    if(!inQue[v]){
                        que.push(v);
                        inQue[v] = true;
                    }
                }
            }
        }
        return pre[t] != -1;
    }

    int ford_fulkerson(int &maxFlow)
    {
        int sum = 0, u, v, minFlow, i;
        maxFlow = 0;
        while(SPFA()){
            minFlow = INF;
            for(u = pre[t], v = t;  u != -1; v = u, u = pre[u]){
                i = path[v];
                minFlow = min(minFlow, G.edges[i].cap);
            }

            maxFlow += minFlow;
            for(u = pre[t], v = t;  u != -1; v = u, u = pre[u]){
                i = path[v];
                G.edges[i].cap -= minFlow;
                G.edges[i^1].cap += minFlow;
                sum += minFlow*G.edges[i].cost;
            }
        }
        return sum;
    }
};

const int MAX_N = 58;
int N, M, K,
    orders[MAX_N][MAX_N],
    supply[MAX_N][MAX_N],
    cost[MAX_N][MAX_N][MAX_N];

int getMinCost(int foodId)
{
    MinCost poj2516;
    int i, j, s, t, maxFlow, sumOrder, res;

    s = M+N+1, t = M+N+2;
    poj2516.s = s, poj2516.t = t;
    sumOrder = 0;

    for(i = 1; i <= M; i++)
        poj2516.G.addEdge(s, i, supply[i][foodId], 0);

    for(i = 1; i <= N; i++){
        poj2516.G.addEdge(i + M, t, orders[i][foodId], 0);
        sumOrder += orders[i][foodId];
    }

    for(i = 1; i <= M; i++)
        for(j = 1; j <= N; j++)
            poj2516.G.addEdge(i, j+M, INF, cost[foodId][j][i]);

    res = poj2516.ford_fulkerson(maxFlow);
    if(sumOrder != maxFlow)
        return -1;
    else
        return res;
}

int main()
{
    //freopen("in.txt", "r", stdin);

    int i, j, t, temp, sum;
    while(~scanf("%d%d%d", &N, &M, &K) && (N+M+K)){

        for(i = 1; i <= N; i++)
            for(j = 1; j <= K; j++)
                scanf("%d", &orders[i][j]);

        for(i = 1; i <= M; i++)
            for(j = 1; j <= K; j++)
                scanf("%d", &supply[i][j]);

        for(t = 1; t <= K; t++)
            for(i = 1; i <= N; i++)
                for(j = 1; j <= M; j++)
                    scanf("%d", &cost[t][i][j]);

        sum = 0;
        for(t = 1; t <= K; t++){
            temp = getMinCost(t);
            if(temp != -1)
                sum += temp;
            else{
                sum = -1;
                break;
            }
        }

        printf("%d\n", sum);
    }

    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值