poj2516 最小费用最大流

#include "stdio.h"  // 最小费用最大流 poj 2516
#include "string.h"
#include "queue"
using namespace std;
#define N 115
#define INF 1000000000

struct node {
	int u,v,w,k;
	int next;
}edge[8*N*N];

int store[N];
int n,m,k,ans,idx;
int head[N],dis[N],route[N],mark[N];
int shop[N][N],supply[N][N],cost[N][N];

void init();
void EK(int start,int end);  
int SPFA(int start,int end);  
void adde(int u,int v,int w,int k);  
void addedge(int u,int v,int w,int k);  

int main()
{
	int sum;
	int i,j,tt;
	int sum1[N],sum2[N];
	while(scanf("%d %d %d",&n,&m,&k))
	{
		tt=k;
		if(n==0 && m==0 && k==0)	return 0;
		memset(sum1,0,sizeof(sum1));
		memset(sum2,0,sizeof(sum2));
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=k;j++)
			{
				scanf("%d",&shop[i][j]);
				sum1[j]+=shop[i][j];  //N家商店需要第j件物品的总件数
			}
		}
		for(i=1;i<=m;i++)
		{
			for(j=1;j<=k;j++)
			{
				scanf("%d",&supply[i][j]);
				sum2[j]+=supply[i][j];   //M处仓库供应第j件物品的总件数
			}
		}
		sum = 0;   //答案初始化(sum记录结果)
		bool flag=true;
		for(tt=1;tt<=k;tt++)
		{
			if(sum1[tt]>sum2[tt]) 
				flag=false;
			init();
			int start=0,end=n+m+1;
			for(i=1;i<=n;i++)
			{
				for(j=1;j<=m;j++)
				{
					scanf("%d",&cost[i][j]);
					adde(j,i+m,cost[i][j],INF);
				}
			}
			for(j=1;j<=m;j++)
				adde(start,j,0,supply[j][tt]);
			for(i=1;i<=n;i++)
			{
				store[i] = idx;
				adde(i+m,end,0,shop[i][tt]);
			}
			while(SPFA(start,end))
				EK(start,end);
			sum += ans;
		}
		if(flag==false)
			printf("-1
");
		else
			printf("%d
",sum);
	}
	return 0;
}

void init()
{
	ans = 0;
	idx = 0;
	memset(head,-1,sizeof(head));
}

void adde(int u,int v,int w,int k)  //对其中的一条再加上一条流量为0的回路  
{  
    addedge(u,v,w,k);  
    addedge(v,u,-w,0);  
}  
  
void addedge(int u,int v,int w,int k)  //邻接表建边  
{  
    edge[idx].u = u;  
    edge[idx].v = v;  
    edge[idx].w = w;  
    edge[idx].k = k;  
    edge[idx].next = head[u];  
    head[u] = idx;  
    idx++;  
}  

int SPFA(int start,int end)  //找一条存在流量的最小费用流(存在流量就行)  
{  
    int i;  
    memset(mark,false,sizeof(mark));  //初始化标记数组mark[];  
    memset(route,-1,sizeof(route));   //ruote[]记录流量路径(存下一条边的下标)  
    for(i=start;i<=end;i++)      dis[i] = INF;  
    dis[start] = 0;  
    queue<int> q;  
    q.push(start);  
    mark[start] = true;  
    int x,y;  
    while(!q.empty())  
    {  
        x = q.front();  
        for(i=head[x];i!=-1;i=edge[i].next)  
        {  
            y = edge[i].v;  
            if(edge[i].k && dis[y] > dis[x] + edge[i].w)  
            {  
                dis[y] = dis[x] + edge[i].w;  
                route[y] = i;   //route[]里面存的为边的下标  
                if(mark[y] == false)  
                {   
                    mark[y] = true;  
                    q.push(y);  
                }  
            }  
        }  
        q.pop();  
        mark[x] = false;  //对出队列的点的标记还原  
    }  
    if(dis[end] == INF) return 0;  
    return 1;  
}  
  
void EK(int start,int end)  
{  
	int s=INF;
    int x,y;  
	y = route[end];
	while(y!=-1)
	{
		if(s>edge[y].k)
			s = edge[y].k;
		y = route[edge[y].u];
	}
    y = route[end];  
    while(y!=-1)  
    {  
        x = y^1;  //很特别的处理;  
        edge[y].k -= s;  //对流量进行处理(正减反加)  
        edge[x].k += s;  
        ans += edge[y].w*s;  
        y = route[edge[y].u]; //通过route[]访问路径上的下一个节点  
    }
}  

原文地址:https://www.cnblogs.com/ruo-yu/p/4411996.html