最小费用最大流poj2516

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <map>
#include <set>
#include <vector>
#include <queue>
#define LL long long
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1e3+10;
struct node{
    int to,flow,cost;
    int next;
}edge[10000];
int head[N];//前向星
int sK[N][N];//商店需求量
int hK[N][N];//仓库存储量
int mK[N][N];//仓库到商店的费用
int sN[N];//所有商店一共需要第K种物品多少
int hN[N];//所有仓库一共存储第K种物品多少
int pre[N];//记录前驱,记录的是edge的编号
int n,m,k,top;
int s,e,ans;
void init(){
    top = 0,s = 0,e = n+m+1;
    memset(head,-1,sizeof(head));
}
void add(int u,int v,int f,int c){
    edge[top]={v,f,c,head[u]};
    head[u] = top++;
}
int dis[N];
bool vis[N];
bool EK_spfa(){
    queue<int>q;
    memset(dis,inf,sizeof(dis));
    memset(vis,false,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; ~i; i = edge[i].next){
            if(dis[edge[i].to] > dis[u]+edge[i].cost&&edge[i].flow){
                dis[edge[i].to] = dis[u]+edge[i].cost;
                pre[edge[i].to] = i;
                if(!vis[edge[i].to]){
                    vis[edge[i].to] = true;
                    q.push(edge[i].to);
                }
            }
        }
    }
    return pre[e]!=-1;
}
bool EK_Max_Flow(int t){
    int cost_ans,flow_ans,mn;
    cost_ans = flow_ans = 0;
    while(EK_spfa()){
        mn = inf;
        for(int i = pre[e]; ~i; i = pre[edge[i^1].to]){
            mn = min(mn,edge[i].flow);
        }
        for(int i = pre[e]; ~i; i = pre[edge[i^1].to]){
            edge[i].flow -= mn;
            edge[i^1].flow += mn;
            cost_ans += edge[i].cost*mn;
        }
        flow_ans += mn;
    }
    if(flow_ans != sN[t])return true;
    ans += cost_ans;
    return false;
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&k),n||m||k){
        //商店
        memset(sN,0,sizeof(sN));
        memset(hN,0,sizeof(hN));
        for(int i = 1; i <= n; ++i){
            for(int j = 1; j <= k; ++j){
                scanf("%d",&sK[i][j]);
                sN[j] += sK[i][j];
            }
        }
        //仓库
        for(int i = 1; i <= m; ++i){
            for(int j = 1; j <= k; ++j){
                scanf("%d",&hK[i][j]);
                hN[j] += hK[i][j];
            }
        }
        bool flag = false;

        for(int i = 1; i <= k; ++i){
            if(sN[i]>hN[i])flag=true;
        }
        ans = 0;
        for(int i = 1; i <= k; ++i){
            for(int j = 1; j <= n; ++j){
                for(int l = 1; l <= m; ++l){
                    scanf("%d",&mK[j][l]);
                }
            }
            if(flag)continue;
            init();
            for(int j = 1; j <= m; ++j){
                add(s,j,hK[j][i],0);
                add(j,s,0,0);
            }
            for(int j = 1; j <= n; ++j){
                add(j+m,e,sK[j][i],0);
                add(e,j+m,0,0);
            }
            for(int j = 1; j <= m; ++j){
                for(int l = 1; l <= n; ++l){
                    add(j,l+m,inf,mK[l][j]);
                    add(l+m,j,0,-mK[l][j]);
                }
            }
            flag = EK_Max_Flow(i);
        }
        if(flag){
            printf("-1\n");
        }
        else{
            printf("%d\n",ans);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值