封装“最小费用最大流”的一个类_poj2516

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值