Poj 2516 Minimum Cost【费用流Min_Cost_Max_flow】

Minimum Cost
Time Limit: 4000MS Memory Limit: 65536K
Total Submissions: 15826 Accepted: 5531

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

Source


题目大意:


有n个点需要购买物品,有m个供货点,有k种物品。

接下来n行,每行k个数,表示这个点需要多少个这些种类的物品。

接下来m行,每行k个数,表示这个供货点对应有多少个这些种类的库存。

接下来K个N*M的矩阵,每个n行m列,表示第k种物品:第j个供货商给i号顾客送货每单位需要的花费。


思路:


1、一开始搞的时候直接将一个点拆成4个点去搞、建图,跑费用流,实力TLE..................点最多可能达到:3*50+3*50+2个.而且边多的离谱....


2、然后参考了大牛们的思路:因为K是互相独立的,没有影响的,那么就将K拆开跑,一共跑K次费用流。点最多可以达到:50+50+2个,而且边少的离谱.....


3、这样我们就做到了优化时间复杂度.然后建图:

①建立源点,将其连入每一个供货商,没有花费,其容量为供货商对应当前这种物品有的库存。

②建立汇点,将每个顾客连入供货商,没有花费,其容量为顾客需要的对应当前这种物品的数量。

③将每一个供货商能够提供给顾客商品的情况都连上边,其费用为其单位花费,其容量设定为INF。


4、建好图之后,跑K遍费用流,如果发现某一次费用流并没有达到满流的情况,那么标记上,之后输出-1.


Ac代码:


#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
#define INF 0x3f3f3f3f
struct node
{
    int from;
    int to;
    int num;
    int w;
    int f;
    int next;
}e[15151515];
int a[300][100];
int need[300][100];
int dis[350];
int vis[350];
int pre[350];
int path[350];
int head[350];
int n,m,k,ss,tt,cont,sum;
void add(int from,int to,int w,int f)
{
    e[cont].to=to;
    e[cont].w=w;
    e[cont].f=f;
    e[cont].num=cont;
    e[cont].next=head[from];
    head[from]=cont++;
}
int SPFA()
{
    memset(vis,0,sizeof(vis));
    memset(path,-1,sizeof(path));
    memset(pre,-1,sizeof(pre));
    for(int i=0;i<=tt;i++)dis[i]=0x3f3f3f3f;
    vis[ss]=1;
    dis[ss]=0;
    queue<int >s;
    s.push(ss);
    while(!s.empty())
    {
        int u=s.front();
        s.pop();vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].to;
            int w=e[i].w;
            int f=e[i].f;
            if(f&&dis[v]>dis[u]+w)
            {
                dis[v]=dis[u]+w;
                pre[v]=u;
                path[v]=e[i].num;
                if(vis[v]==0)
                {
                    vis[v]=1;
                    s.push(v);
                }
            }
        }
    }
    if(dis[tt]!=0x3f3f3f3f)return 1;
    else return 0;
}
int Min_costflow()
{
    int maxflow=0;
    int ans=0;
    while(SPFA()==1)
    {
        int minn=0x3f3f3f;
        for(int i=tt;i!=ss;i=pre[i])
        {
            minn=min(minn,e[path[i]].f);
        }
        for(int i=tt;i!=ss;i=pre[i])
        {
            e[path[i]].f-=minn;
            e[path[i]^1].f+=minn;
        }
        ans+=minn*dis[tt];
        maxflow+=minn;
    }
    if(maxflow==sum)
    return ans;
    else return -1;
}
void Solve()
{
    ss=m+n+1;
    tt=ss+1;
    sum=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=k;j++)
        {
            scanf("%d",&need[i][j]);
        }
    }
    for(int i=1;i<=m;i++)
    {
        for(int j=1;j<=k;j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    int flag=0;
    int output=0;
    for(int z=1;z<=k;z++)
    {
        cont=0;
        sum=0;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=m;i++)
        {
            add(ss,i,0,a[i][z]);
            add(i,ss,0,0);
        }
        for(int i=1;i<=n;i++)
        {
            add(i+m,tt,0,need[i][z]);
            sum+=need[i][z];
            add(tt,i+m,0,0);
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                int tmp;
                scanf("%d",&tmp);
                add(j,i+m,tmp,INF);
                add(i+m,j,-tmp,0);
            }
        }
        int tt=Min_costflow();
        output+=tt;
        if(tt==-1)flag=1;
    }
    if(flag==1)
    {
        printf("-1\n");
    }
    else printf("%d\n",output);
}
int main()
{
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        if(n+m+k==0)break;
        Solve();
    }
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值