加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

POJ PKU 2516 最小费用流

(2010-09-01 19:26:40)
标签:

poj

pku

2516

最小费用流

it

分类: 网络流

题目描述:

有k种商品,n个商店,m个提供商。

对于每一个商店有k个数字,表示这个商店需要各个物品的个数。

对于每一个提供商也有k个数字,表示这个提供商拥有各个物品的个数。

然后,对于每个物品k,都有n行m列的矩阵。

i行j列表示:

从j提供商向i商店运送一个k商品的代价是多少。

问你:

提供商能不能满足所有的商店需求。

能的话,输出最小的代价。

解题报告:

可以发现,各个物品总的代价是独立的。

所以对于每个物品独立的进行最小费用流处理。

源点s,连接所有商店,费用0,容量是各个商店对k物品的需求。

汇点t,所有提供商连接t,费用0,容量是各个提供商拥有k物品的个数。

商店i和提供商j连接,费用是j到i运送物品k的代价,容量是无穷。

代码如下:

#include<iostream>
using namespace std;
int n, m, k;
#define size 102
#define Max 0x7fffffff
struct edge{int from, to, val, next, cost;} e[5400];
int v[size], cnt, pre[size], pos[size], dis[size], que[size * 10];
bool vst[size];
void insert(int from, int to, int val, int cost)
{
    e[cnt].from = from, e[cnt].to = to, e[cnt].val = val;
    e[cnt].cost = cost, e[cnt].next = v[from];v[from] = cnt++;
    e[cnt].from = to, e[cnt].to = from;e[cnt].val = 0;
    e[cnt].cost = -cost, e[cnt].next = v[to];v[to] = cnt++;
}
bool spfa(int s, int t, int n)
{
    memset(pre, -1, sizeof(int) * n); memset(vst, 0, sizeof(bool) * n);
    int head, tail; head = tail = 0;
    for(int i = 0; i < n; i++) dis[i] = Max;
    que[tail++] = s; pre[s] = s; dis[s] = 0; vst[s] = 1;
    while(head != tail)
    {
        int id = que[head++]; vst[id] = 0;
        id = v[id];
        while(id != -1)
        {
            if (e[id].val > 0 && dis[e[id].from] + e[id].cost < dis[e[id].to])
            {
                dis[e[id].to] = dis[e[id].from] + e[id].cost;
                pre[e[id].to] = e[id].from; pos[e[id].to] = id;
                if (!vst[e[id].to])
                {
                    vst[e[id].to] = 1;
                    que[tail++] = e[id].to;
                }
            }
            id = e[id].next;
        }
    }
    return pre[t] != -1;
}
int MinCostFlow(int s, int t, int n, int &flow)
{
    int cost = 0;
    flow = 0;
    while(spfa(s, t, n))
    {
        int fl = Max;
        for(int i = t; i != s; i = pre[i])
            if (e[pos[i]].val < fl) fl = e[pos[i]].val;
        flow += fl; cost += dis[t] * fl;
        for(int i = t; i != s; i = pre[i])
        {
            e[pos[i]].val -= fl;
            e[pos[i] ^ 1].val += fl;
        }
    }
    return cost; // flow是最大流值
}
int need[50][50], have[50][50], g[50][50][50], sum[50];
int main()
{
    while(scanf("%d%d%d", &n, &m, &k) && (n || m || k))
    {
        memset(sum, 0, sizeof(int) * (k + 1));
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= k; j++)
                scanf("%d", &need[i][j]), sum[j] += need[i][j];
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= k; j++)
                scanf("%d", &have[i][j]);
        for(int k1 = 1; k1 <= k; k1++)
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= m; j++)
                    scanf("%d", &g[k1][i][j]);
        int ans = 0;
        bool flag = true;
        for(int i = 1; i <= k; i++)
        {
            int s = 0, t = n + m + 1;
            memset(v, -1, sizeof(int) * (t + 1)); cnt = 0;
            for(int j = 1; j <= n; j++) insert(s, j, need[j][i], 0);
            for(int j = 1; j <= m; j++) insert(j + n, t, have[j][i], 0);
            for(int j = 1; j <= n; j++)
                for(int j2 = 1; j2 <= m; j2++)
                    insert(j, j2 + n, 2000000000, g[i][j][j2]);
            int flow = 0;
            int cost = MinCostFlow(s, t, t + 1, flow);
            if (flow != sum[i]) {flag = false;break;}
            ans += cost;
        }
        if (!flag) printf("-1\n");
        else printf("%d\n", ans);
    }
    return 0;
}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有