网络流——最大流算法(C语言实现)

最大流算法

最大流算法是图论的一个重要算法,可以应用在管道运输等方面。
现在给出一个有向图,点1为出发点,点6为收点,计算由点1到点6最大可以流过多少值
在这里插入图片描述
先考虑一下贪心算法,即用广度优先搜索发现一条通路,之后就把这条通路
的运输率打到最大化!
如,上图中存在(1,3,5,6)这样的通路,现在把这条运输通路尽可能的占满。

紧接着,又有(1,2,5,6)这样的通路,于是
在这里插入图片描述
最后,有(1,2,4,6)这样的通路,于是:
在这里插入图片描述
现在,从1流出的管道,和流入6的管道已经全部用上,成功找到了一个最大流。
但是,贪心算法在寻找最大网络流时,并不总是可行的
如:若首先找到了(1,2,5,6),则
在这里插入图片描述
现在,由1到6已经不存在通路,所以贪心的思想并不能准确的找到最大流

**

于是,我们采用另外一种算法,来找到最大流。

**
即,在找的由出发点流向终止点的一条通路的同时,生成一条大小相等的方向相反的通路!

同样,假如一开始便找到了(1,2,5,6)这样的通路,并且最大限度的使用这一条通路

在这里插入图片描述
于是,现在便存在了(1,3,5,2,4,6)这样的通路,以相同的算法执行这一条通路。
在这里插入图片描述
知道由点1到点6没有通路,算法结束!

显然,在这两次操作中,有一次2->5的运输,也有一次5->2的运输
这两次运输的方向是相反的,若把方向相反的运输给抵消掉,则运输方式大致与第一次的贪心算法的运输方式相同。

个人看法:
每一次运输之后,建立一个当前通道相反的,等大的通道,相当于是给了程序一个反悔的机会。即,当发现没有通路时,可以改变之前走过的路径,从而找到最大流。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct node;
typedef struct node * pNode;
struct node{
	int num;
	int toPower;
	pNode next;
};
struct item{
	int key;
	int n_dis;
	int n[10];
};
struct queue;
typedef struct queue * pQueue;
struct queue{
	int num;
	pQueue next;
};
void show(pNode *,int);
pNode * creat(pNode*,int);
pNode end(pNode);
int search(pNode *,int);
struct item road(pNode *,int);
pQueue push(pQueue,int);
pQueue out(pQueue);
int main()
{
	pNode * list;
	pNode current,temp;
	int a,b,c,N,i,j,k;
	scanf("%d",&N);
	list=(pNode *)malloc(sizeof(pNode)*N);
	
	for(i=0;i<N;i++){
		list[i]=(pNode)malloc(sizeof(struct node));
		temp=list[i];
		temp->num=i+1;
		temp->next=NULL;
		while(scanf("%d",&a)==1){
			current=(pNode)malloc(sizeof(struct node));
			current->num=a;
			scanf("%d",&a);
			current->toPower=a;
			temp->next=current;
			current->next=NULL;
			temp=current;
		}
		getchar();
	}
	show(list,N);
	//在现有的有向图的基础上形成一个无向图
	list=creat(list,N);
	show(list,N);
	puts("");
	while(search(list,N)){
		struct item x=road(list,N);
		for(i=0;i<x.n_dis;i++){
			printf("%d ",x.n[i]);
	    }
	    puts("") ;
		for(i=1;i<x.n_dis;i++){
			
			int n1=x.n[i-1];
			int n2=x.n[i];
			current=list[n1-1]->next;
			
			while(current->num!=n2&&current->next!=NULL){
				current=current->next;
				
			}
			
			current->toPower--;
			current=list[n2-1]->next;
			while(current->num!=n1&&current->next!=NULL){
				current=current->next;
			}
			current->toPower++;
		}
		
		show(list,N);
	}
	
}
struct item road(pNode *list,int N){
	int a,b,i,j;
	pNode current,temp;
	pQueue head=NULL;

	int x[10];
	struct item dis[N];
	for(i=0;i<N;i++){
		dis[i].key=0;
		dis[i].n_dis=0;
	}
	x[0]=1;
	dis[0].n[0]=1;
	dis[0].key=1;
	dis[0].n_dis=1;
	int count=1;
	current=list[0]->next;
	do{
		while(current!=NULL){
			if((current->toPower)!=0&&dis[current->num-1].key==0){
				dis[current->num-1].key=1;
				head=push(head,current->num);
				for(i=0;i<count;i++){
					dis[current->num-1].n[i]=x[i];
				}
				dis[current->num-1].n[i]=current->num;
				dis[current->num-1].n_dis=i+1;
			}
			current=current->next;
		}
		
		current=list[head->num-1]->next;
		count=dis[head->num-1].n_dis;
		for(i=0;i<count;i++)
			x[i]=dis[head->num-1].n[i];
		head=out(head);
		while(current!=NULL){
			if(current->toPower!=0&&dis[current->num-1].key==0){
				dis[current->num-1].key=1;
				head=push(head,current->num);
				for(i=0;i<count;i++){
					dis[current->num-1].n[i]=x[i];
				}
				dis[current->num-1].n[i]=current->num;
				dis[current->num-1].n_dis=i+1;
			}
			current=current->next;
		}
	}while(head!=NULL);
	
	return dis[N-1];
}
int search(pNode * list,int N){ //用广度优先搜索来判断是否还存在通路; 
	int a,b,key=0,i,j,dis[N];
	pNode current,temp;
	pQueue head=NULL,kong;
	for(i=0;i<N;i++){
		dis[i]=0;
	}
	dis[0]=1;
	current=list[0]->next; //不需要记录距离
	do{
		while(current!=NULL){
			if(current->num==6){
				return 1;
			}
			if(current->toPower!=0&&dis[current->num-1]==0){
				head=push(head,current->num);
				dis[current->num-1]=1;
			}
			current=current->next;
		}
		current=list[head->num-1]->next;
		head=out(head);
		while(current!=NULL){
			if(current->num==6){
				return 1;
			}
			if(current->toPower!=0&&dis[current->num-1]==0){
				head=push(head,current->num);
				dis[current->num-1]=1;
			}
			current=current->next;
		}
	}while(head!=NULL); 
	return 0;
}
pQueue push(pQueue head,int num){
	pQueue temp,current;
	temp=(pQueue)malloc(sizeof(struct queue));
	if(head==NULL){
		head=temp;
		temp->num=num;
		temp->next=NULL;
	}
	else{
		current=head;
		while(current->next!=NULL){
			current=current->next;
		}
		current->next=temp;
		temp->next=NULL;
		temp->num=num;
	}
	return head;
}
pQueue out(pQueue head){
	if(head->next==NULL){
		free(head);
		return NULL;
	}
	else{
		pQueue current=head->next;
		free(head);
		return current;
	}
}
pNode end(pNode current){
	while(current->next!=NULL){
		current=current->next;
	}
	return current;
}
pNode *creat(pNode * list,int N)
{
	int a,b,i;
	pNode current,temp,kong;
	for(i=0;i<N;i++){
		current=list[i]->next;
		while(current!=NULL){
		    if(current->toPower!=0){
		    	a=current->num;
		    	kong=(pNode)malloc(sizeof(struct node));
		    	temp=end(list[a-1]);
		    	temp->next=kong;
		    	kong->next=NULL;
		    	kong->num=i+1;
		    	kong->toPower=0;
		    	
			}
			current=current->next;
		}
	}
	return list;
}
void show(pNode * list,int N){
	int i,j,k;
	pNode current;
	for(i=0;i<N;i++){	
		printf("%d->:",list[i]->num);
		current=list[i];
		current=current->next;
		while(current!=NULL){
			printf("%d(%d) ",current->num,current->toPower);
			current=current->next;
		}
		puts("");
	}
}

以邻接表储存数据,贴上测试数据和运行结果

测试数据:
6
2 3 3 2 +
3 1 4 3 5 4 +
5 2 +
6 2 +
6 3 +
+```

生成的邻接表
1->:2(3) 3(2)
2->:3(1) 4(3) 5(4)
3->:5(2)
4->:6(2)
5->:6(3)
6->:

由于有向图中有些是单向通道,所以要在这个基础上,对相连的点建立双向通道。

1->:2(3) 3(2)
2->:3(1) 4(3) 5(4) 1(0)
3->:5(2) 1(0) 2(0)
4->:6(2) 2(0)
5->:6(3) 2(0) 3(0)
6->:4(0) 5(0)

最后的结果
1->:2(0) 3(0)
2->:3(1) 4(1) 5(3) 1(3)
3->:5(0) 1(2) 2(0)
4->:6(0) 2(2)
5->:6(0) 2(1) 3(2)
6->:4(2) 5(3)

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值