#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,只要扩展一下就可以拿去验证自己代码的正确性了(过了的话至少初步说明是正确的),贴出代码,方便自己以后查询套用~~