POJ 2516 Minimum Cost(最小费用最大流)

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


拆点不行,就拆网。。。。。


题意:有N个店,M个供货商,K种商品。已知供货商的仓库里每种商品的数量以及每种商品运送到每个店的费用,每个店铺对各种商品的需求数量,求最少花费。 

Input 

第一行:N,M,K。
然后1 - N行,每行 K列 ,第I行第J个数代表 第I个店铺 需要第J种物品多少件。
然后 N+1 - M行  ,每行 K列 , 第I行第J个数代表 第I个供货商 有第J种物品多少件。
然后是K个矩阵  ,每个N行M列,第ji个矩阵的第i行第j列代表着第j个供货商给第i个店铺发第ji种货物一件需要的费用。哎哟,我日。。。。

坑题一道啊,感觉已经不是在考查网络流,而是在考察对 繁琐数据输入 的Debug能力,弄了一上午,坑我啊。。。


思路一开始思路就是错的,上去就拆点,将供货商和店铺对应着K种商品,把每个供货商拆成K个,店铺拆成K个,写了一半感觉不对劲,50*50 + 50*50 + 50,肯定超时。


    既然拆点不行,那么就拆网呗。。。把对应所有商品的整个网络,拆成K个单种商品的网络,求出单个商品的子网络的最小费用,最后进行累加就是整个网络的最小费用


建图

增设两个点,源点s = 0,汇点t = N+M+1,源点与供货商相连,费用0,容量为当前单种商品的供给量

供货商与店铺相连费用已知,容量为正无穷。

店铺与汇点相连,费用0,容量为当前单种商品的需求。


AC代码。。。

552 KB407 msC++

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
const int maxn = 110;
const int maxm = 10000;
const int inf = 1e8;
#define MIN INT_MIN
#define MAX 1e6
#define LL long long
#define init(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i = a;i<b;i++)
#define max(a,b) (a>b)?(a):(b)
#define min(a,b) (a>b)?(b):(a)
using namespace std;
struct node
{
    int u,v,w,cap,next;
}edge[maxm];
int pre[maxn],dis[maxn],head[maxn],cnt;
bool vis[maxn];
int n,m;
void add(int u,int v,int c,int cap)
{
    edge[cnt].u=u;
    edge[cnt].v=v;
    edge[cnt].w=c;
    edge[cnt].cap=cap;
    edge[cnt].next=head[u];
    head[u]=cnt++;

    edge[cnt].u=v;
    edge[cnt].v=u;
    edge[cnt].w=-c;
    edge[cnt].cap=0;
    edge[cnt].next=head[v];
    head[v]=cnt++;
}
int spfa(int s,int t)
{
    queue<int>q;
    while(q.empty()==false) q.pop();
    q.push(s);
    memset(vis,0,sizeof(vis));
    memset(pre,-1,sizeof(pre));
    FOR(i,s,t+1)
        dis[i] = inf;
    dis[s]=0;
    while(!q.empty())
    {
       int u=q.front();
        q.pop();
        vis[u] = 0;
        for(int i=head[u];i!=-1;i=edge[i].next)
        {
            if(edge[i].cap && dis[edge[i].v]>dis[u]+edge[i].w)
            {
                dis[edge[i].v]=dis[u]+edge[i].w;
                pre[edge[i].v] = i;
                if(!vis[edge[i].v])
                {
                    vis[edge[i].v]=1;
                    q.push(edge[i].v);
                }
            }
        }

    }
    if(dis[t] != inf)
        return 1;
    else
        return 0;
}
int MinCostMaxFlow(int s,int t)
{
	int flow=0,cost=0;
    while(spfa(s,t))
    {
		int df = inf;
		for(int i = pre[t];i!=-1;i=pre[edge[i].u])
		{
			if(edge[i].cap<df)
				df = edge[i].cap;
		}
		flow += df;
        for(int i=pre[t];i!=-1;i=pre[edge[i].u])
        {
            edge[i].cap -= df;
            edge[i^1].cap += df;
        }
	cost += dis[t] * df;
    }
    return cost;
}
void initt()
{
    cnt=0;
    memset(head,-1,sizeof(head));
}

int main()
{
    int gong[51],qiu[51];
    int k,s,t;
    int need[200][200],gei[200][200];
    while(scanf("%d%d%d",&n,&m,&k),n,m,k)
    {
        init(need);init(gei);
        init(gong);init(qiu);
        s = 0,t = n+m+1;
        FOR(i,1,n+1)
        {
            FOR(j,1,k+1)
                {
                    scanf("%d",&need[i][j]);
                    qiu[j] += need[i][j];
                }
        }
        FOR(i,1,m+1)
        {
            FOR(j,1,k+1)
            {
                scanf("%d",&gei[i][j]);
                gong[j] += gei[i][j];
            }
        }
        bool flag = 1;
        FOR(i,1,k+1)
        {
            if(gong[i]<qiu[i])//如果单种商品的供给量不满足该商品的需求量,直接打印-1
            {
                flag = 0;
                break;
            }
        }
        int cost,yao,money = 0;

        FOR(ji,1,k+1)
        {
             initt();
         
             FOR(i,1,n+1)
             {
                FOR(j,1,m+1)
               {
                   scanf("%d",&cost);
                   if(flag==0) continue;
                   add(j,m+i,cost,inf);//供给商和店主的流量为正无穷
               }
             }
             if(flag==0) continue;
             FOR(i,1,n+1)
             {
                 add(m+i,t,0,need[i][ji]);//店铺和汇点的费用为0,流量为店对该种商品的需求
             }
             FOR(i,1,m+1)
             {
                 add(s,i,0,gei[i][ji]);//源点对供应商的费用为0,流量为供货商对该种商品的供给
             }
           money += MinCostMaxFlow(s,t);
        }
        (flag==0)?puts("-1"):printf("%d\n",money);
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值