算法导论 最大流 前置重贴标签法

本文介绍了如何使用C语言实现基于算法导论中的前置重贴标签法求解最大流问题。通过初始化图、残余网络、初始化前向流、重新标记和推流等步骤,详细展示了算法的具体过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <stdio.h>  
#include <stdlib.h>  
#include <limits.h>  
  
//图节点

typedef struct AdjacentNodeType
{
	int index;
	struct AdjacentNodeType *nextNeighbor;
}AdjacentNode,*pAdjacentNode;

typedef struct VertexNode    
{    
	int index;
    char name;  
    int h;  
    int e;  
	pAdjacentNode current;
	pAdjacentNode head;
	struct VertexNode *next;
	struct VertexNode *pre;
}Vertex,*pVertex;    
    
//图    
typedef struct     
{    
    int vn;    
    int **E;  //容量C作为边矩阵的值  
    pVertex *V;    
    int **f; //流值  
    int **rE; // 残留边
	pVertex L; //前置重贴标签用到的链表,在initGraph()中初始化
}Graph,*pGraph;    

void generateAdjacentList(pGraph g,int s,int t)
{
	for(int i=0;i<g->vn;i++)
	{
		for(int j=0;j<g->vn;j++)
		{
			if(g->E[i][j]>0 || g->E[j][i]>0)
			{			
				pAdjacentNode adj=(pAdjacentNode)malloc(sizeof(AdjacentNode));
				adj->index=j;
				adj->nextNeighbor=g->V[i]->head;
				g->V[i]->head=adj;
			}			
		}
	}
}

//根据算法导论 图26-6初始化图 
pGraph initGraph()    
{    
    pGraph g=(pGraph)malloc(sizeof(Graph));    
    g->vn=6; 
	int s=0,t=g->vn-1;
    pVertex vs=(pVertex)malloc(sizeof(Vertex));    
    vs->name='s';
	vs->index=0;
    pVertex v1=(pVertex)malloc(sizeof(Vertex));    
    v1->name='1'; 
	v1->index=1;
    pVertex v2=(pVertex)malloc(sizeof(Vertex));    
    v2->name='2';
	v2->index=2;
    pVertex v3=(pVertex)malloc(sizeof(Vertex));    
    v3->name='3';
	v3->index=3;
    pVertex v4=(pVertex)malloc(sizeof(Vertex));    
    v4->name='4';
	v4->index=4;
    pVertex vt=(pVertex)malloc(sizeof(Vertex));    
    vt->name='t';
	vt->index=5;
    
    g->V=(pVertex*)malloc(g->vn*sizeof(pVertex));    
    g->V[0]=vs;    
    g->V[1]=v1;    
    g->V[2]=v2;    
    g->V[3]=v3;    
    g->V[4]=v4;   
    g->V[5]=vt;  	

	for(int i=0;i<g->vn;i++)
	{
		g->V[i]->current=g->V[i]->head=NULL;
		g->V[i]->pre=g->V[i]->next=NULL;
	}

	g->L=NULL;
	for(int i=g->vn-1;i>=0;i--)
	{
		if(i==s || i==t)
			continue;
		g->V[i]->next=g->L;
		if(g->L)
			g->L->pre=g->V[i];
		g->L=g->V[i];
	}

    g->E = (int**)malloc(g->vn*sizeof(int*));    
    g->f= (int**)malloc(g->vn*sizeof(int*));  
    g->rE= (int**)malloc(g->vn*sizeof(int*));   
    for(int i=0;i<g->vn;i++)    
    {    
        g->E[i]=(int*)malloc(g->vn*sizeof(int));    
        g->f[i]=(int*)malloc(g->vn*sizeof(int));    
        g->rE[i]=(int*)malloc(g->vn*sizeof(int));   
    }    
    for(int i=0;i<g->vn;i++)    
    {    
        for(int j=0;j<g->vn;j++)    
        {   
            g->E[i][j]=0;  
            //g->f[i][j]=0;    
        }    
    }    
    g->E[0][1]=16;  
    g->E[0][2]=13;  
    g->E[1][3]=12;    
    g->E[2][1]=4;    
    g->E[2][4]=14;    
    g->E[3][2]=9;  
    g->E[3][5]=20;  
    g->E[4][3]=7;  
    g->E[4][5]=4;

	generateAdjacentList(g,s,t);

    return g;    
}    
  
void initResidualNetwork(pGraph g)  
{  
    for(int i=0;i<g->vn;i++)    
    {    
        for(int j=0;j<g->vn;j++)    
        {  
            g->rE[i][j]=0;  
        }  
    }  
    for(int i=0;i<g->vn;i++)    
    {    
        for(int j=0;j<g->vn;j++)    
        {   
            if(g->E[i][j]>0)               
            {  
                int x=g->E[i][j]-g->f[i][j];  
                if(x>0)  
                    g->rE[i][j]=x;  
				if(g->f[i][j]>0)  
                    g->rE[j][i]=g->f[i][j];
            }  
        }    
    }    
}  
  
void initializePreflow(pGraph g,int s)  
{  
    for(int i=0;i<g->vn;i++)  
    {  
        g->V[i]->e=g->V[i]->h=0;  
    }  
    for(int i=0;i<g->vn;i++)    
    {    
        for(int j=0;j<g->vn;j++)    
        {   
            g->f[i][j]=0;    
        }    
    }  
    g->V[s]->h=g->vn;  
    for(int i=0;i<g->vn;i++)  
    {  
        if(i != s)  
        {  
            g->f[s][i]=g->E[s][i];  
            g->V[i]->e=g->E[s][i];  
            g->V[s]->e -= g->E[s][i];  
        }  
    }  
}  

void push(pGraph g,int u,int v)  
{  
    if(g->V[u]->e<=0)  
        return;  
    if(g->V[u]->h != g->V[v]->h+1)  
        return;  
    if(g->rE[u][v]<=0)  
        return;  
    int d=g->V[u]->e < g->rE[u][v] ? g->V[u]->e : g->rE[u][v];  
    //更新流  
    if(g->E[u][v]>0)  
    {  
        g->f[u][v]+=d;  
    }  
    else  
    {  
        g->f[v][u]-=d;  
    }  
    //更新超额流  
    g->V[u]->e-=d;  
    g->V[v]->e+=d;  
    //更新残存图  
    if(g->E[u][v]>0)  
    {  
        int x=g->E[u][v]-g->f[u][v];   
        g->rE[u][v]=x;
		if(g->f[u][v]>0)  
			g->rE[v][u]=g->f[u][v];
    }  
}  
  
//进入函数时,默认保证g->V[u]->e>0  
//返回能从u进行push的邻接顶点位置  
//返回-1代表残留图中该顶点无邻接点  
int relabel(pGraph g,int u)  
{  
    int minh=INT_MAX,minPos;  
    for(int i=0;i<g->vn;i++)  
    {  
        if(i==u)  
            continue;  
        if(g->rE[u][i]>0)  
        {  
            if(g->V[i]->h<g->V[u]->h)  
                return i;  
            else  
            {  
                if(g->V[i]->h<minh)  
                {  
                    minh=g->V[i]->h;  
                    minPos=i;  
                }  
            }  
        }  
    }  
    if(minh<INT_MAX)  
    {  
        g->V[u]->h=minh+1;  
        return minPos;  
    }  
    else//u没有邻接点时走到这里  
        return -1;  
}

void discharge(pGraph g,int u)
{
	while(g->V[u]->e>0)
	{
		pAdjacentNode pv=g->V[u]->current;
		if(pv==NULL)
		{
			relabel(g,u);
			g->V[u]->current=g->V[u]->head;
		}
		else if(g->rE[u][pv->index]>0 && g->V[u]->h == g->V[pv->index]->h+1)
		{
			push(g,u,pv->index);
		}
		else
			g->V[u]->current=pv->nextNeighbor;
	}
}

void relabelToFront(pGraph g,int s,int t)
{
	initializePreflow(g,s);
	initResidualNetwork(g);
	for(int i=0;i<g->vn;i++)
	{
		if(i==s || i==t)
			continue;
		g->V[i]->current=g->V[i]->head;
	}
	pVertex pu=g->L;
	while(pu!=NULL)
	{
		int oldHeight=pu->h;
		discharge(g,pu->index);
		if(pu->h>oldHeight)
		{
			//链表中需要移动的节点是头节点则不移动
			if(pu!=g->L)
			{
				pu->pre->next=pu->next;
				if(pu->next)
					pu->next->pre=pu->pre;
				pu->next=g->L;
				g->L->pre=pu;
				pu->pre=NULL;
				g->L=pu;
			}
		}
		pu=pu->next;
	}
}

void printFlow(pGraph g)  
{  
    for(int i=0;i<g->vn;i++)  
    {  
        for(int j=0;j<g->vn;j++)  
        {  
            if(g->E[i][j]>0)  
                printf("%c->%c (%d/%d)\n",g->V[i]->name,g->V[j]->name,g->f[i][j],g->E[i][j]);  
        }  
    }  
}  

int calcuMaxFlow(pGraph g,int s)
{
	int maxFlow=0;
	for(int i=0;i<g->vn;i++)
	{
		if(i==s)
			continue;
		if(g->f[s][i]>0)
			maxFlow+=g->f[s][i];
	}
	return maxFlow;
}

void main()  
{  
    pGraph g=initGraph();  
	int s=0,t=g->vn-1;
    relabelToFront(g,s,t);  
	int maxFlow=calcuMaxFlow(g,s);
	printf("Max Flow is:%d\n",maxFlow);
    printFlow(g);  
    getchar();  
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值