poj2516

题意:有k种物品,m个供应商,n个收购商。每个供应商和收购商都需要一些种类的物品若干。每个供应商与每个收购商之间的对于不同物品的运费是不同的。求满足收购商要求的情况下,最小运费。

分析:最小费用最大流,最大流的前提下求最小费用。这题我们可以把k种物品分开计算,每次对一种物品进行最小费用最大流计算。如果不分开算会超时。对于每种物品,从源到供应商连接,容量为供应商的储存量,费用为0。采购商到汇连边,容量为需求量,费用为0。供应商到采购商连边,容量为无穷,费用为对应的运费。

最小费用最大流的计算流程大致是:每次找到一条根据费用来看的最短路,然后对这条最短路进行增加流量,直到所有路径流量都不能增加为止。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
usingnamespace std;

#define N 110
#define E 10000
#define inf 1000000000

#define typef int
// type of flow
#define typec int
// type of dis
const typef inff =0x3f3f3f3f;
// max of flow
const typec infc =0x3f3f3f3f;
// max of dis
int shop[N][N], supply[N][N];
struct network
{
int nv, ne, pnt[E], nxt[E];
int vis[N], que[N], head[N], pv[N], pe[N];
int sum;
typef flow, cap[E];
typec cost, dis[E], d[N];
void addedge(int u, int v, typef c, typec w)
{
pnt[ne]
= v;
cap[ne]
= c;
dis[ne]
=+w;
nxt[ne]
= head[u];
head[u]
= (ne++);
pnt[ne]
= u;
cap[ne]
=0;
dis[ne]
=-w;
nxt[ne]
= head[v];
head[v]
= (ne++);
}
int mincost(int src, int sink)
{
int i, k, f, r;
typef mxf;
for (flow =0, cost =0;;)
{
memset(pv,
-1, sizeof(pv));
memset(vis,
0, sizeof(vis));
for (i =0; i < nv; ++i)
d[i]
= infc;
d[src]
=0;
pv[src]
= src;
vis[src]
=1;
for (f =0, r =1, que[0] = src; r != f;)
{
i
= que[f++];
vis[i]
=0;
if (N == f)
f
=0;
for (k = head[i]; k !=-1; k = nxt[k])
if (cap[k] && dis[k] + d[i] < d[pnt[k]])
{
d[pnt[k]]
= dis[k] + d[i];
if (0== vis[pnt[k]])
{
vis[pnt[k]]
=1;
que[r
++] = pnt[k];
if (N == r)
r
=0;
}
pv[pnt[k]]
= i;
pe[pnt[k]]
= k;
}
}
if (-1== pv[sink])
break;
for (k = sink, mxf = inff; k != src; k = pv[k])
if (cap[pe[k]] < mxf)
mxf
= cap[pe[k]];
flow
+= mxf;
cost
+= d[sink] * mxf;
for (k = sink; k != src; k = pv[k])
{
cap[pe[k]]
-= mxf;
cap[pe[k]
^1] += mxf;
}
}
return cost;
}
void build(int n, int m, int o)
{
nv
= n + m +2;
ne
=0;
int src =0;
int sink =1;
sum
=0;
memset(head,
-1, sizeof(head));
for (int i =0; i < n; i++)
{
addedge(i
+2, sink, shop[i][o], 0);
sum
+= shop[i][o];
}
for (int i =0; i < m; i++)
addedge(src, i
+2+ n, supply[i][o], 0);
for (int i =0; i < n; i++)
for (int j =0; j < m; j++)
{
int a;
scanf(
"%d", &a);
addedge(j
+2+ n, i +2, inf, a);
}
}
};

int n, m, o;

void input()
{
for (int i =0; i < n; i++)
for (int j =0; j < o; j++)
scanf(
"%d", &shop[i][j]);
for (int i =0; i < m; i++)
for (int j =0; j < o; j++)
scanf(
"%d", &supply[i][j]);
}

int main()
{
//freopen("t.txt", "r", stdin);
while (scanf("%d%d%d", &n, &m, &o), n | m | o)
{
bool ok =true;
int ans =0;
input();
for (int i =0; i < o; i++)
{
network g;
g.build(n, m, i);
if (ok)
ans
+= g.mincost(0, 1);
if (g.flow != g.sum)
ok
=false;
}
if (ok)
printf(
"%d\n", ans);
else
printf(
"-1\n");
}
return0;
}
posted @ 2011-05-17 18:58  金海峰  阅读(1286)  评论(0编辑  收藏  举报