POJ 2516 Minimum Cost

最小費.

主要是這題有K種貨物搞得關係很複雜, 開始建圖卡住, 其實把k種貨物分開來建k次圖跑k次就好了.

然後判斷最大流和是否滿足需求, 若滿足則輸出最小費和, 若不滿足, 則輸出-1.

貌似還可以用KM


代碼:

//最小費用流
//	建k次圖... 最小費

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 200;
const int MAXM = 40005;
const int INF = 1<<30;
int mincost,maxflow;
int n,m;
int U[MAXM],V[MAXM],cap[MAXM],flow[MAXM],cost[MAXM],next[MAXM];
int head[MAXN],pre[MAXN],Edge[MAXN],dis[MAXN];
int num;
void addEdge(int u,int v,int Cap,int Cost)
{
	flow[num] = flow[num+1] = 0;
	V[num] = v;
	U[num] = u;
	cap[num] = Cap;
	cost[num] = Cost;
	next[num] = head[u];
	head[u] = num++;
	
	V[num] = u;
	U[num] = v;
	cap[num] = 0;
	cost[num] = -Cost;
	next[num] = head[v];
	head[v] = num++;
}

void MCMF(int st,int ed)
{
	queue<int> q;
	memset(flow,0,sizeof(flow));
	mincost = maxflow = 0;
	for(;;)
	{
		bool inq[MAXN];
		for(int i = st;i <= ed;++i)		dis[i] = (i == st ? 0 : INF);
		memset(inq,0,sizeof(inq));
		q.push(st);
		while(!q.empty())
		{
			int u = q.front();	q.pop();
			inq[u] = 0;
			for(int e = head[u];e != -1;e = next[e])
			{
				if(cap[e] > flow[e] && dis[u] + cost[e] < dis[V[e]])
				{
					dis[V[e]] = dis[u] + cost[e];
					pre[V[e]] = U[e]; 
					Edge[V[e]] = e;
					if(!inq[V[e]])
					{
						q.push(V[e]);
						inq[V[e]] = 1;
					}
				}
			}
		}//SPFA增廣
		if(dis[ed] == INF)	break;
		int delta = INF;//delta爲可改進量
		for(int u = ed;u != st;u = pre[u])
			delta = min(delta,cap[Edge[u]] - flow[Edge[u]]);//遍歷最短路徑的邊,並修改可改進量
		for(int u = ed;u != st;u = pre[u])
		{
			flow[Edge[u]] += delta;//更新正向流量
			flow[Edge[u] ^ 1] -= delta;//通過異或1取得反向邊的序號,並更新反向流量
		}
		mincost += dis[ed] * delta;
		maxflow += delta;
	}
}

int sell[52][52];
int buy[52][52];
int value[52][52][52];
int main()
{
	//	buildGraphs
	int K;
	while(scanf("%d%d%d", &n, &m, &K) == 3)
	{
		if(!n && !m && !K) break;
		int need = 0;
		int totflow = 0;
		int totcost = 0;
		for(int i=0; i<n; i++)
			for(int k=0; k<K; k++)
			{
				scanf("%d", &buy[k][i]);	//n個買家
				need+=buy[k][i];
			}
		for(int i=0; i<m; i++)
			for(int k=0; k<K; k++)
			{
				scanf("%d", &sell[k][i]);	//m個倉庫
			}
		for(int k=0; k<K; k++)
			for(int i=0; i<n; i++)
				for(int j=0; j<m; j++)
				{
					scanf("%d", &value[k][i][j]);		//j->i
				}
		for(int k=0; k<K; k++)
		{
			num = 0;
			memset(head,-1,sizeof(head));				// 0 賣 1~m 買 m+1~m+n 匯 m+n+1
			for(int i=0; i<m; i++)
			{
				addEdge(0,i+1,sell[k][i],0);
			}
			for(int i=0; i<n; i++)
			{
				addEdge(i+1+m, m+n+1, buy[k][i], 0);
			}
			for(int i=0; i<n; i++)
				for(int j=0; j<m; j++)	//賣
				{
					addEdge(j+1, i+1+m, INF, value[k][i][j]);
				}
			//MCMF
			MCMF(0,n+m+1);
			totcost += mincost;
			totflow += maxflow;
			//printf("%d\n",mincost);
		}
		if(totflow!=need) totcost = -1;
		printf("%d\n", totcost);
	}

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章