#include <stdio.h>
#include <string.h>
#include <deque>
// 最小费用最大流
namespace pifu
{
char buf[4000000];
class KsPOJAllocator
{
int m_pos;
public:
KsPOJAllocator() : m_pos(0){}
~KsPOJAllocator(){}
void* allocate(int e_size){ void * p = &buf[m_pos]; m_pos+=e_size; return p; }
void* allocate_initvalue(int e_size, int e_value = 0){ void *p = &buf[m_pos]; m_pos+=e_size; memset(p, e_value, e_size); return p;}
void deallocate(void * e_p){}
void reset(){ m_pos = 0; }
};
static KsPOJAllocator g_POJAlloc;
static const int PP_SIZE = sizeof(void *);
// network stream
struct ks_ns_edge_t
{
int v;
int c;
int f;
int value;
struct ks_ns_edge_t *next, *reverse;
};
class KsMinValueMaxStream
{
public:
int N, s, t;
int maxStream;
int minValue;
bool bCalculated, bFind;
ks_ns_edge_t **ppEdge;
ks_ns_edge_t **ppPath; // 记录路径
bool *used;
int *d;
int *pCounts;
public:
KsMinValueMaxStream(int e_N, int e_s = 0, int e_t = 1, int e_mode = 0)
: N(e_N), s(e_s), t(e_t), bCalculated(false), maxStream(0), minValue(0)
{
ppEdge = (ks_ns_edge_t **)g_POJAlloc.allocate_initvalue(N*PP_SIZE);
ppPath = (ks_ns_edge_t **)g_POJAlloc.allocate_initvalue(N*PP_SIZE);
used = (bool*)g_POJAlloc.allocate_initvalue(N*sizeof(bool));
d = (int*)g_POJAlloc.allocate_initvalue(N*sizeof(int));
pCounts = (int*)g_POJAlloc.allocate_initvalue(N*sizeof(int));
}
~KsMinValueMaxStream()
{
ks_ns_edge_t *p, *q;
for (int i = 0; i < N; i++)
{
p = ppEdge[i];
while (p != NULL)
{
q = p->next;
g_POJAlloc.deallocate(p);
p = q;
}
}
g_POJAlloc.deallocate(ppEdge);
g_POJAlloc.deallocate(ppPath);
g_POJAlloc.deallocate(used);
g_POJAlloc.deallocate(d);
g_POJAlloc.deallocate(pCounts);
}
void addEdge(int u, int v, int cuv, int cvu, int costuv, int costvu)
{
ks_ns_edge_t *puv = (ks_ns_edge_t *)g_POJAlloc.allocate_initvalue(sizeof(ks_ns_edge_t));
ks_ns_edge_t *pvu = (ks_ns_edge_t *)g_POJAlloc.allocate_initvalue(sizeof(ks_ns_edge_t));
puv->c = cuv;
puv->v = v;
puv->reverse = pvu;
puv->next = ppEdge[u];
puv->value = costuv;
ppEdge[u] = puv;
pvu->c = cvu;
pvu->v = u;
pvu->reverse = puv;
pvu->next = ppEdge[v];
pvu->value = costvu;
ppEdge[v] = pvu;
}
void Calculate()
{
int minf, temp, ccost;
ks_ns_edge_t *p;
if (bCalculated)
return;
while(true)
{
ccost = spfaEx();
if (ccost == 0x77777777 || ppPath[t] == NULL)
break;
p = ppPath[t];
minf = p->reverse->c - p->reverse->f;
while (ppPath[p->v] != NULL)
{
p = ppPath[p->v];
temp = p->reverse->c - p->reverse->f;
if (minf > temp)
minf = temp;
}
maxStream += minf;
minValue += ccost * minf;
p = ppPath[t];
while (p != NULL)
{
p->f -= minf;
p->reverse->f += minf;
p = ppPath[p->v];
}
}
bCalculated = true;
}
private:
int spfaEx()
{
static const int MAXD = 0x77777777;
memset(used, 0, N);
memset(d, 0x77, N*sizeof(int));
memset(pCounts, 0, N*sizeof(int));
memset(ppPath, 0, N*PP_SIZE);
d[s] = 0;
used[s] = true;
std::deque<int> que;
que.push_back(s);
ks_ns_edge_t *p;
pCounts[s] = 1;
bool bAnnulus = false;
int i, j, k;
while (!que.empty())
{
j = que.front();
que.pop_front();
used[j] = false;
p = ppEdge[j];
while (p != NULL)
{
if (p->f < p->c && d[p->v] > d[j]+p->value)
{
d[p->v] = d[j]+p->value;
ppPath[p->v] = p->reverse;
if (!used[p->v])
{
if (que.empty()) que.push_back(p->v);
else{
k = que.front();
if (d[p->v] < d[k]) que.push_front(p->v);
else que.push_back(p->v);
}
used[p->v] = true;
pCounts[p->v]++;
if (pCounts[p->v] >= N)
{
bAnnulus = true;
break;
}
}
}
p = p->next;
}
if (bAnnulus) break;
}
if (bAnnulus)
return MAXD;
return d[t];
}
};
}
using namespace pifu;
#define MM 50
int N, M, K;
int Nneed[MM][MM];
int Mhave[MM][MM];
int Kcost[MM][MM][MM];
inline int ks_min(int a, int b){ return a < b ? a : b; }
int main()
{
int i, j, k, t;
pifu::KsMinValueMaxStream * pms;
int costResult;
for (;;)
{
scanf("%d%d%d", &N, &M, &K);
if (N == 0) break;
for (i = 0; i < N; i++)
for (j = 0; j < K; j++)
scanf("%d", &Nneed[i][j]);
for (i = 0; i < M; i++)
for (j = 0; j < K; j++)
scanf("%d", &Mhave[i][j]);
for (i = 0; i < K; i++)
for (j = 0; j < N; j++)
for (k = 0; k < M; k++)
scanf("%d", &Kcost[i][j][k]);
costResult = 0;
for (i = 0; i < K; i++)
{
g_POJAlloc.reset();
pms = new pifu::KsMinValueMaxStream(M+N+2, 0, M+N+1, 1);
for (j = 0; j < M; j++)
{
if (Mhave[j][i] != 0)
pms->addEdge(0, j+1, Mhave[j][i], 0, 0, 0);
}
for (j = 0; j < N; j++)
{
if (Nneed[j][i] != 0)
{
pms->addEdge(M+1+j, M+N+1, Nneed[j][i], 0, 0, 0);
}
}
for (j = 0; j < M; j++)
for (k = 0; k < N; k++)
{
t = ks_min(Mhave[j][i], Nneed[k][i]);
if (t != 0)
pms->addEdge(j+1, M+1+k, t, 0, Kcost[i][k][j], -Kcost[i][k][j]);
}
pms->Calculate();
t = 0;
for (j = 0; j < N; j++)
t +=Nneed[j][i];
if (pms->maxStream != t)
{
costResult = -1;
break;
}
costResult += pms->minValue;
}
printf("%d\n", costResult);
}
return 0;
}
时不时去poj上练习一些题目,碰到最大流等写起来比较费劲的代码时,总是比较痛苦,所以想着整理到类里面,以后只要套用就可以了,于是写了一个最大流的类,每个节点的边用数组表示,用最简单的实现方法,dfs寻找增广路径。结果还真过了poj上的4000题。只是后来想着调用时边的相关值很难写,所以边改成链表重新写了一个,结果一直超时,链表就是比普通数组慢啊!!好在撞到一道最小费用最大流的题2516,只要扩展一下就可以拿去验证自己代码的正确性了(过了的话至少初步说明是正确的),贴出代码,方便自己以后查询套用~~