POJ 2516 Minimum Cost(最小费用流)

还是建图问题,一定要仔细

网络流难点:1.问题的转化,2.图的构建

https://vjudge.net/problem/POJ-2516

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<cmath>
#define ll long long
#define mod 1000000007
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 505;
const int maxm = 105*105+2*105;
bool vis[maxn];
int pre[maxn], d[maxn], head[maxn];
int cnt;
int n, m, k;
int u, v, w, c;
int s, t;
int need[55][55];
int have[55][55];
int sum[555];
struct node
{
    int s, to, next, w, c;
}e[maxm];
void init()
{
    memset(head, - 1, sizeof(head));
    s = 0, t = n + m + 1;
    cnt = 0;
}
void addedge(int u, int v, int w, int c)//w是路径花费,c是流量
{
    e[cnt].s = u;
    e[cnt].to = v;
    e[cnt].w = w;
    e[cnt].c = c;
    e[cnt].next = head[u];
    head[u] = cnt ++;

    e[cnt].s = v;
    e[cnt].to = u;
    e[cnt].w = -w;
    e[cnt].c = 0;
    e[cnt].next = head[v];
    head[v] = cnt ++;
}
bool spfa()
{
    memset(vis, 0, sizeof(vis));
    memset(pre, -1, sizeof(pre));
    memset(d, 0x3f, sizeof(d));
    queue<int> q;
    q.push(s);
    d[s] = 0;
    vis[s] = 1;
    while(! q.empty())
    {
        int h = q.front();
        q.pop();
        vis[h] = 0;
        for(int i = head[h]; ~i; i = e[i].next)
        {
            if(e[i].c)
            {
                int v = e[i].to;
                if(d[h] + e[i].w < d[v])
                {
                    d[v] = d[h] + e[i].w;
                    pre[v] = i;
                    if(! vis[v])
                    {
                        vis[v] = 1;
                        q.push(v);
                    }
                }
            }
        }
    }
    if(d[t] == inf) return 0;
    else return 1;
}
int EK()
{
    int cost = 0;
    int tt, minc;
    while(spfa())
    {
        tt = t;
        minc = inf;
        while(pre[tt] != -1)
        {
            minc = min(e[pre[tt]].c, minc);
            tt = e[pre[tt]].s;
        }
        tt = t;
        while(pre[tt] != -1)
        {
            e[pre[tt]].c -= minc;
            e[pre[tt]^1].c += minc;
            tt = e[pre[tt]].s;
        }
        cost += d[t] * minc;
    }
    return cost;
}

int main()
{
    while(scanf("%d%d%d", &n, &m, &k) != EOF && (n + m + k))
    {
        bool flag = 0;
        memset(sum, 0, sizeof(sum));
        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]);
                sum[j] += have[i][j];
            }
        }
        int ans = 0;
        for(int now = 1; now <= k; now ++)
        {
            init();
            for(int i = 1; i <= m; i ++)
                addedge(0, i, 0, have[i][now]);
            for(int i = 1; i <= n; i ++)
                addedge(m + i, n + m + 1, 0, need[i][now]);
            int cost;
            for(int i = 1; i <= n; i ++)
                for(int j = 1; j <= m; j ++)
            {
                scanf("%d", &cost);
                addedge(j, m + i, cost, min(need[i][now], have[j][now]));
            }
            for(int i = 1; i <= k; i ++)
            {
                if(sum[i] < 0)
                {
                    flag = 1;
                    break;
                }
            }
            if(flag) continue;
            ans += EK();
        }
        if(flag) printf("-1\n");
        else printf("%d\n", ans);
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值