poj 2516

来源:互联网 发布:外国知乎瞧不起中国 编辑:程序博客网 时间:2024/05/21 09:49

题目概述

市场上有K种货物流通,编号1到K,有N家店,编号1到N,每家都需要一定量的各种货,M家供货商,编号1到M,每家库存有一定量的各种货,从供货商运货到店面会产生运费,问供货商库存能否满足商店的货物需求,若能满足,求最小运输费用

时限

4000ms/12000ms

输入

第一行整数N,M,K,其后N行,每行K个整数,为该商店需要的各种货数量,货按编号升序给出,商店按编号升序给出,其后M行,每行K个整数,为该供货商库存各种货数量,按升序给出,其后K个N行M列的矩阵,行号代表商店,列号代表供货商,值为供货商运送一单位该种货物到商店的运费,按货号升序给出矩阵,输入到N=M=K=0结束

限制

0< N,M,K<50

输出

每行一个数,若无法满足需求,为-1,否则为最小运费

样例输入

1 3 3
1 1 1
0 1 1
1 2 2
1 0 1
1 2 3
1 1 1
2 1 1

1 1 1
3
2
20

0 0 0

样例输出

4
-1

讨论

图论,网络流,费用流,最小增广路算法,这个题说的非常直白,一看就知道是费用流,构图上也几乎没有难度,源点,供货商,商店,汇点,每种货物单独考虑,单独构图,源点到供货商残量为库存量,费用0,供货商到商店残量无穷大,费用就是单位货物的运费,这点需要稍微留心,其反向边残量0,费用为运费的相反数,不是0,像额这种刚入门的很难发现这条错误,商店到汇点残量为需求量,费用0,其他货物类别同理构图,当供不应求时,这张图的最大流会小于所有商店对该货物需求的和,由此进行判断
实现层面上,没有什么难度,只是由于输入比较奇怪,读入的时候需要稍微细心一点
虽说开个三维数组相当浪费,但是着实是非常方便,加上算法也不是什么高级货色,暂且如此

题解状态

5112K,391MS,C++,1878B

题解代码

#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;#define INF 0x3f3f3f3f#define MAXN 54#define memset0(a) memset(a,0,sizeof(a))int N, M, K, S, T;//商店数 供货商数 货类别数 源点 汇点int R[MAXN][MAXN * 2][MAXN * 2], W[MAXN][MAXN * 2][MAXN * 2], dis[MAXN * 2], from[MAXN * 2], require[MAXN];//残量矩阵 费用矩阵 最短路长度 父节点 每种货物的总需求量queue<int>q;bool inq[MAXN * 2];int bellman_ford(int K, int N)//第一个参数是货的编号 第二个是图上节点总数{    int least = 0, most = 0;//最小费用 最大流    while (1) {//下面就是bellman_ford算法 稍微改一下就可以        int flow = INF;        for (int p = 0; p < N; p++)            dis[p] = INF;        dis[S] = 0;        q.push(S);        while (!q.empty()) {            int a = q.front();            q.pop();            inq[a] = 0;            for (int p = 0; p < N; p++)                if (R[K][a][p] && dis[p] > dis[a] + W[K][a][p]) {//得有残量才能松弛                    dis[p] = dis[a] + W[K][a][p];                    from[p] = a;                    flow = min(flow, R[K][a][p]);                    if (!inq[p]) {                        q.push(p);                        inq[p] = 1;                    }                }        }        if (dis[T] == INF) {//当没有增广路时            if (most < require[K])//供不应求                return -1;            return least;        }        most += flow;        least += flow*dis[T];        for (int p = T; p; p = from[p]) {            int i = from[p];            R[K][i][p] -= flow;            R[K][p][i] += flow;//顺原路返回进行增广        }    }}int fun(){    T = M + N + 1;//构造的汇点 源点是0    for (int p = 1; p <= N; p++)        for (int i = 0; i < K; i++) {            scanf("%d", &R[i][M + p][T]);//input//商店到汇点            require[i] += R[i][M + p][T];        }    for (int p = 1; p <= M; p++)        for (int i = 0; i < K; i++)            scanf("%d", &R[i][S][p]);//input//读入源点到供货商    for (int p = 0; p < K; p++)        for (int i = 1; i <= N; i++)            for (int u = 1; u <= M; u++) {                scanf("%d", &W[p][u][M + i]);//input//读入供货商到商店                W[p][M + i][u] = -W[p][u][M + i];//构造反向边                R[p][u][M + i] = INF;            }    int cost = 0;    for (int p = 0; p < K; p++) {        int add = bellman_ford(p, M + N + 2);        if (add == -1)            return -1;        cost += add;    }    return cost;}int main(void){    //freopen("vs_cin.txt", "r", stdin);    //freopen("vs_cout.txt", "w", stdout);    while (~scanf("%d%d%d", &N, &M, &K) && (N || M || K)) {//input        printf("%d\n", fun());//output        memset0(R);        memset0(W);        memset0(require);    }}

EOF

0 0
原创粉丝点击