【原创】【KM算法】POJ 2516 Minimum cost(拆点+多次KM)

来源:互联网 发布:数据存储四种方式 编辑:程序博客网 时间:2024/05/21 10:54

Minimum Cost POJ - 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 (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

题目大意

Dearboy是一个销售商,他卖K种货物略去一万字。这一天,有N个商家需要这K种货物,而Dearboy有M个仓库,这些商店也都有这K种货物。从不同的仓库运不同的货物到不一样的商家都要花不一样的钱。如果可以满足所有需求,求最小费用,如果不能,输出-1。

题目分析

首先,此题可以用最小费用流做,然而,,,,我们还是用km算法吧。

这道题目的第一个难点就是输入
让我们来分析输入。

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.

先读入三个整数N,M,K,其意义如上。看起来数据规模挺小的。
然后读入N行,每行K个。表示N个不同商家的需求数量,每个商家对每个货物的需求都介于0~3。
再来是M行,每行K个。表示M个仓库有的各种货物的数量,介于0~3。

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.

然后是K个矩阵。每个矩阵都是N*M的大小(不是M*N,与一开始的输入顺序是不一样的),第k个矩阵的第i行第j列表示从j仓库一个k货物i商家的价钱。(同样注意顺序,是从j到i的钱。)

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

题目有多组数据,以三个0结束。

所以说搞信竞,要学好英语和数学呀。

很坑的输入环节搞定,然后我们来分析怎么做。

首先我们不考虑k种货物,只考虑单种货物。
会出现什么情况呢?—一个点不只代表一个货物。
拆点前
要知道,km是把一个一个的人匹配起来,而不是一个顶俩的大胖子
所以说,必须采取措施!
拆点!
我们一刀把大胖子砍成小矮子,然后就可以匹配啦!
拆点后
点搞定了,然后是边。
边很简单,拆点前是多少就多少。

最后的一个问题,它不止一种货物。

现在有两种解决方案,
其一:把所有点全部拆开在一个巨大的图里,然后进行KM;
其二:进行k次km,每次处理一种。

看到这里,我相信聪明的读者一定知道哪个方案好了吧?

所以,

详见代码

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define ac(b) memset(b,0x3f,sizeof b)#define cc(b) memset(b,0,sizeof b)#define sz(b) sizeof bconst int BIG=55;const int MAXN=2505;const int INF=0x3fffffff;bool Read(int &p){    p=0;    char c=getchar();    while(c<'0' || c>'9') c=getchar();    while(c>='0' && c<='9')         p=p*10+c-'0',c=getchar();    return 1;}int dbx[MAXN],dby[MAXN],linky[MAXN],pre[MAXN],slack[MAXN],C[MAXN][MAXN];bool vis[MAXN];int n,m,k;int needs[BIG][BIG],has[BIG][BIG],costs[BIG][BIG][BIG];int allneeds[BIG],allhas[BIG];int X[MAXN],cnx,Y[MAXN],cny;void bfs(int s){    int px,py=0,yy=0,d;    cc(pre); ac(slack);    linky[py]=s;    do    {        px=linky[py]; d=INF; vis[py]=1;        for(int i=1;i<=cny;i++)        {            if(!vis[i])            {                if(dbx[px]+dby[i]-C[px][i]<slack[i])                    slack[i]=dbx[px]+dby[i]-C[px][i],pre[i]=py;                if(slack[i]<d) d=slack[i],yy=i;            }        }        for(int i=0;i<=cny;i++)        {            if(vis[i]) dbx[linky[i]]-=d,dby[i]+=d;            else slack[i]-=d;        }        py=yy;    }while(linky[py]!=0);    while(py) linky[py]=linky[pre[py]],py=pre[py];}int km(){    cc(dbx),cc(dby),cc(linky);    for(int i=1;i<=cnx;i++)         cc(vis),bfs(i);    int lov=0;    for(int i=1;i<=cny;i++)        if(linky[i]) lov+=dbx[linky[i]]+dby[i];    return lov;}int main(){    while(Read(n) and Read(m) and Read(k) and n+m+k)    {        cc(allneeds); cc(allhas);        for(int i=1;i<=n;i++)             for(int j=1;j<=k;j++)                Read(needs[i][j]),allneeds[j]+=needs[i][j];        for(int i=1;i<=m;i++)            for(int j=1;j<=k;j++)                Read(has[i][j]),allhas[j]+=has[i][j];        for(int l=1;l<=k;l++)//从j卖家运一个l货物到i买家            for(int i=1;i<=n;i++)                for(int j=1;j<=m;j++)                    Read(costs[i][j][l]);        bool f=0;        for(int i=1;i<=k && !f;i++)            if(allneeds[i]>allhas[i]) puts("-1"),f=1;        if(f) continue;        int ans=0;        for(int l=1;l<=k;l++)        {            cnx=0; cny=0;            for(int i=1;i<=n;i++)                while(needs[i][l]--) X[++cnx]=i;            for(int i=1;i<=m;i++)                while(has[i][l]--) Y[++cny]=i;            for(int i=1;i<=cnx;i++)                for(int j=1;j<=cny;j++)                    C[i][j]=-costs[X[i]][Y[j]][l];            ans+=km();        }        printf("%d\n",-ans);    }}
原创粉丝点击