poj 2516 最小费用最大流


Language:
Default

Minimum Cost

Time Limit: 4000MS   Memory Limit: 65536K
Total Submissions: 14334   Accepted: 4908

Description

Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (marked from 1 to M), each provides K different kinds of goods (marked from 1 to K). Once shopkeepers order goods, Dearboy should arrange which supply place provide how much amount of goods to shopkeepers to cut down the total cost of transport.

It‘s known that the cost to transport one unit goods for different kinds from different supply places to different shopkeepers may be different. Given each supply places‘ storage of K kinds of goods, N shopkeepers‘ order of K kinds of goods and the cost to transport goods for different kinds from different supply places to different shopkeepers, you should tell how to arrange the goods supply to minimize the total cost of transport.

Input

The input consists of multiple test cases. The first line of each test case contains three integers N, M, K (0 < N, M, K < 50), which are described above. The next N lines give the shopkeepers‘ orders, with each line containing K integers (there integers are belong to [0, 3]), which represents the amount of goods each shopkeeper needs. The next M lines give the supply places‘ storage, with each line containing K integers (there integers are also belong to [0, 3]), which represents the amount of goods stored in that supply place.

Then come K integer matrices (each with the size N * M), the integer (this integer is belong to (0, 100)) at the i-th row, j-th column in the k-th matrix represents the cost to transport one unit of k-th goods from the j-th supply place to the i-th shopkeeper.

The input is terminated with three "0"s. This test case should not be processed.

Output

For each test case, if Dearboy can satisfy all the needs of all the shopkeepers, print in one line an integer, which is the minimum cost; otherwise just output "-1".

Sample Input

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

Sample Output

4
-1

一道最小费用最大流的题,难点在建图,不是建图难,而是坑,不能一次性建图,这样会超时不说还会出现负环,但是本人一直不懂为什么会出现负环,大神方便的可以给个指教么,感觉这题的我写的代码上面的注释还是不错的,适合小白去看。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<climits>
#include<queue>
#define MAXN 110
using namespace std;
struct Edge
{
    int s,t,f,c,next;
}edge[12000];//构造邻接表
int N,M,K;
int head[MAXN];//构造邻接表
int pre[MAXN];//纪录路径
bool isq[MAXN];//纪录一个点是否在队列里面
int dist[MAXN];//纪录到该点的最小费用
int store[55][55];//商店的需求量
int market[55][55];//市场的供应量
int good[55][55][55];//从市场到商店的费用
int SUM[55];//所有的商店对第i件商品的需求量之和
int ALL[50];//所有的市场对第j件商品的供给量之和
int ent;//表示边的编号
int s,t;//表示超级源点超级汇点
int cost;//表示最小的费用
void add(int s,int t,int f,int c)
{
    edge[ent].s=s;
    edge[ent].t=t;
    edge[ent].f=f;
    edge[ent].c=c;
    edge[ent].next=head[s];
    head[s]=ent++;
    edge[ent].s=t;
    edge[ent].t=s;
    edge[ent].f=0;
    edge[ent].c=-c;
    edge[ent].next=head[t];
    head[t]=ent++;
}
int MIN(int a,int b)
{
    return a<b?a:b;
}
bool spfa()
{
    memset(pre,-1,sizeof(pre));//初始化路径为-1
    for(int i=s;i<=t;i++)
    {
        isq[i]=false;//每点开始时均不在队列里面
        dist[i]=INT_MAX;//初始化到每点的最小费用均为INT_MAX
    }
    queue<int>q;
    q.push(s);
    isq[s]=true;//源点s已经放入到队列里面去了
    dist[s]=0;//从源点到源点的距离出回话为0
    while(!q.empty())//当队列为空时优化过程结束,退出循环
    {
        int temp1=q.front();
        q.pop();
        isq[temp1]=false;//该点已经退出队列
        for(int i=head[temp1];i!=-1;i=edge[i].next)//从该点找通过邻接表找所有的以该点为起点的边,从中找出能优化的点
        {
            int temp2=edge[i].t;
            if(edge[i].f&&dist[temp2]>dist[temp1]+edge[i].c)
            {
                dist[temp2]=dist[temp1]+edge[i].c;
                pre[temp2]=i;
                if(!isq[temp2])//如果该点不在队列中,则将该点放入队列中
                {
                    q.push(temp2);
                    isq[temp2]=true;
                }
            }
        }
    }
    return pre[t]!=-1;//如果pre[t]==-1的话说明没有找到从s到t的路径,即已经找到所有的路径了,结束循环
}
int MCMF()
{
    int cost=0;
    while(spfa())
    {
        int minn=INT_MAX;//为找到这个过程中能流过的最大流所加的变量
        for(int i=pre[t];i!=-1;i=pre[i])
        {
            minn=MIN(minn,edge[i].f);
            i=edge[i].s;
        }
        for(int i=pre[t];i!=-1;i=pre[i])
        {
            edge[i].f-=minn;//将该条路径经过的边的流量都减掉该过程能经过的最大流
            edge[i^1].f+=minn;//反向边加上该最大流,从而保证可以反悔
            i=edge[i].s;
        }
        cost+=minn*dist[t];//把每次找到的费用加起来
    }
    return cost;//返回最小费用
}
int main()
{
    int temp,ok;
    while(cin>>N>>M>>K,N+M+K)
    {
        cost=0;
        bool ok=true;//纪录市场能不能满足超市的需求
        memset(SUM,0,sizeof(SUM));
        memset(ALL,0,sizeof(ALL));
        for(int i=1;i<=N;i++)
        {
            for(int j=1;j<=K;j++)
            {
                scanf("%d",&store[i][j]);//第i家商店对第j件商品的需求量
                SUM[j]+=store[i][j];
            }
        }
        for(int i=1;i<=M;i++)
        {
            for(int j=1;j<=K;j++)
            {
                scanf("%d",&market[i][j]);//第i家供货商对第j件商品的供给量
                ALL[j]+=market[i][j];
            }
        }
        for(int i=1;i<=K;i++)
        {
            for(int j=1;j<=N;j++)
            {
                for(int k=1;k<=M;k++)
                {
                    scanf("%d",&good[i][j][k]);//第k家供货商给第j家商店供应第i件商品的单价
                }
            }
        }
        for(int i=1;i<=K;i++)
        {
            if(SUM[i]>ALL[i])
            {
                ok=false;
                break;
            }
        }
        if(ok==false)
        {
            printf("-1\n");//供应满足不了需求,输出-1
        }
        else
        {
            for(int i=1;i<=K;i++)//对第i件物品使用最小费用最大流算法
            {
                ent=0;//初始化边
                memset(head,-1,sizeof(head));//初始化邻接表
                for(int j=1;j<=M;j++)
                {
                    add(0,j,market[j][i],0);//从源点到供货商的边
                }
                for(int j=1;j<=M;j++)
                {
                    for(int k=1;k<=N;k++)
                    {
                        add(j,k+M,INT_MAX,good[i][k][j]);//从供货商到商店的边
                    }
                }
                for(int j=1;j<=N;j++)
                {
                    add(j+M,M+N+1,store[j][i],0);//从商店到汇点的边
                }
                s=0;
                t=M+N+1;
                cost+=MCMF();
            }
            printf("%d\n",cost);
        }
    }
}
时间: 2024-12-26 08:02:30

poj 2516 最小费用最大流的相关文章

hdu 2516 最小费用最大流

原来这个代码超时 #include<stdio.h> #include<queue> #include<string.h> using namespace std; #define N 200 #define inf 0x3fffffff int cap[N][N]; int fee[N][N]; int s,t,sum,pre[N]; int spfa() { queue<int>q; int dis[N],visit[N],u,i; memset(pre

poj 2195 最小费用最大流模板

/*Source Code Problem: 2195 User: HEU_daoguang Memory: 1172K Time: 94MS Language: G++ Result: Accepted Source Code */ #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespa

poj 2135(最小费用最大流)

Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14730   Accepted: 5614 Description When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of

POJ - 2195 最小费用最大流

题意:每个人到每个房子一一对应,费用为曼哈顿距离,求最小的费用 题解:单源点汇点最小费用最大流,每个人和房子对于建边 #include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<cassert> #include<iomanip&

poj 2135 最小费用最大流初步

这个题的意思是农夫约翰要呆人参观他的农场, 刚开始从1开始走, 走到N后又返回1点, 两次不能走相同的路, 问农夫约翰走的最短的路是多少?? 我们可以用最小MCMF来解决这个问题, 对于图中的每一条边, 我们建立了两条流量为1, 费用为边权的边, 再增加一个源点和一个汇点, 源点指向1, 流量为2,费用为0, N指向汇点, 流量为2费用为0, 然后求出最小费用即可, 代码如下: #include <cstdio> #include <algorithm> #include <

POJ 3680 最小费用最大流

这题来源:<算法竞赛经典入门-训练指南>中的367页:区间k覆盖问题. 思路:这题建图比较机智,我刚开始想到能建的图也就是离散化后两个端点连边,流量为1,费用为负的权值(因为求的是最大费用最大流),然后再加上源点和汇点,也就如此而已:但是这样建图样例第二和第四个不正确,因为中间没有联系的没连边,然后k就没用了. 原来最重要的连边是i和i+1之间的连边,流量为k,费用为0:为什么要连这些边呢,刚开始我也没想明白,后面才知道,因为有的端点之间你要让它们产生联系并且受制与k次,那么就得把这些点都连边

POJ 3422 最小费用最大流

链接: http://poj.org/problem?id=3422 题解: 关键是如何处理"只能获取一次"的问题,为此可以为每个点创建伪点,由两条有向边相连.原始点到伪点连一条容量为1,权值为负分数的边:原始点到伪点连一条容量为无穷,权值为0的边.前者表示分数只能拿一次,后者表示第二次第三次--可以继续走这个点,但是不拿分数.负权是因为题目要求的是"最大费用".又因为最多走同一个点K次,所以此处的无穷大取K就行了. 代码: 1 #include <map&g

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

题目链接:http://poj.org/problem?id=2516 Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (mar

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

POJ 2516 Minimum Cost 链接:http://poj.org/problem?id=2516 题意:有M个仓库,N个商人,K种物品.先输入N,M,K.然后输入N行K个数,每一行代表一个商人要购买的物品,其中K个数分别表示要购买的每件商品数.然后是M行K个数,每行表示仓库里的情况,其中K个数分别每种物品的库存量.接下来是K个矩阵,每个矩阵为N*M,分别表示第K种物品从M个仓库运到第N个商人的花费.问能否合理安排,使得花费最少,如果不行就输出-1. 思路: 一开始的时候,竟然构造了