题意:给出n个客户对k种商品的需求量,又给出m个仓库对k种物品的存货量以及对k种物品从i仓库到j客户的一个物品的运费价格,让判断是否可以满足客户需求,然后就是如果满足求出最小的运费.
思路:简单的最小费用最大流,注意建图细节即可。下面解释转自网上。
首先必须判断m个仓库是否有足够的k种商品给n个客户,如果不足,那么明显就是不行的. 下面假设仓库的商品足够的话:
对于每一种商品我们都算出满足满足顾客需求量的最小运费即可.所以我们对K种商品分开处理如下,假设当前处理第x种商品,建图如下:
源点s编号0, m个仓库编号1到m, n个顾客编号m+1到m+n, 汇点编号m+n+1.
从源点s到每个仓库i有边(s, i, 仓库i对商品x的存货量, 0)
从每个仓库i到顾客j有边(i, j, INF, 仓库i到顾客j的单位X商品的运费)
从每个顾客j到汇点t有边(j, t, 顾客j对X商品的需求量, 0)
然后我们求最小费用最大流即可求出N个顾客对第X种商品的最小运费.
#include <cstdio> #include <queue> #include <cstring> #include <iostream> #include <cstdlib> #include <algorithm> #include <vector> #include <map> #include <string> #include <set> #include <ctime> #include <cmath> #include <cctype> using namespace std; #define maxn 300 #define LL long long int cas=1,T; const int INF = 1e9; struct Edge { int from,to,cap,flow,cost; Edge(){} Edge(int u,int v,int c,int f,int co):from(u),to(v),cap(c),flow(f),cost(co){} }; int n,m; struct MCMF { // int s,t; vector<Edge>edges; vector<int>G[maxn]; int inq[maxn]; //是否在队列中 int d[maxn]; int p[maxn]; //上一条弧 int a[maxn]; //可改进量 void init() { for (int i = 0;i<=n+m+1;i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap,int cost) { edges.push_back(Edge(from,to,cap,0,cost)); edges.push_back(Edge(to,from,0,0,-cost)); int mm = edges.size(); G[from].push_back(mm-2); G[to].push_back(mm-1); } bool BellmanFord(int s,int t,int &flow,int &cost) { for (int i = 0;i<=n+m+1;i++) d[i]=INF; memset(inq,0,sizeof(inq)); d[s]=0; inq[s]=1; p[s]=0; a[s]=INF; queue<int>q; q.push(s); while (!q.empty()) { int u = q.front();q.pop(); inq[u]=0; for (int i = 0;i<G[u].size();i++) { Edge &e = edges[G[u][i]]; if (e.cap > e.flow && d[e.to]>d[u]+e.cost) { d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if (!inq[e.to]) { q.push(e.to); inq[e.to]=1; } } } } if (d[t]==INF) return false; //s-t不连通,失败退出 flow+=a[t]; cost+=d[t]*a[t]; int u = t; while (u!=s) { edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; u=edges[p[u]].from; } return true; } int Mincost(int s,int t) { int flow = 0; int cost = 0; while (BellmanFord(s,t,flow,cost)); return cost; } }mc; int need[60][60]; //i顾客对j商品的需求量 int have[60][60]; //i仓库对j商品的供应量 int cost[60][60][60]; //仓库j到i顾客对x商品的运费 int main() { //freopen("in","r",stdin); int k; while (scanf("%d%d%d",&n,&m,&k)!=EOF && n) { int goods[maxn]; int flag = 1; memset(goods,0,sizeof(goods)); for (int i = 1;i<=n;i++) for (int j = 1;j<=k;j++) { scanf("%d",&need[i][j]); goods[j]+=need[i][j]; } for (int i = 1;i<=m;i++) for (int j = 1;j<=k;j++) { scanf("%d",&have[i][j]); goods[j]-=have[i][j]; } for (int h = 1;h<=k;h++) for (int i = 1;i<=n;i++) for (int j = 1;j<=m;j++) scanf("%d",&cost[h][i][j]); for (int i = 1;i<=k;i++) if (goods[i]>0) { flag = 0; break; } if (!flag) { printf("-1\n"); continue; } int mins = 0; // mc.init(); for(int g = 1;g<=k;g++) { mc.init(); for (int i = 1;i<=m;i++) mc.AddEdge(0,i,have[i][g],0); for (int i = 1;i<=n;i++) mc.AddEdge(m+i,m+n+1,need[i][g],0); for (int i = 1;i<=m;i++) for (int j = 1;j<=n;j++) mc.AddEdge(i,j+m,INF,cost[g][j][i]); mins+=mc.Mincost(0,n+m+1); } printf("%d\n",mins); } //scanf("%d",&T); //printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC); return 0; }