网络流(根目录)

这一篇讲有更新,仅提供目录。

网络流介绍

增广路简介

网络流的算法实现

    网络流算法(dinic)

    网络流算法(sap+弧优化)

    网络流算法(分层推进)

网络流建图

    简单建图(HDU - 1532为例)

#include"stdio.h"  
#include"string.h"  
#include"queue"  
#include"stack"  
#include"iostream"  
#include"stdlib.h"  
#define inf 99999999  
#define M 50000  
using namespace std;
struct st
{
	int u, v, w, next;
}edge[M];
int t, head[M], cur[M], q[M], gap[M], dis[M];
void init()
{
	t = 0;
	memset(head, -1, sizeof(head));
}
void add(int u, int v, int w)
{
	edge[t].u = u;
	edge[t].v = v;
	edge[t].w = w;
	edge[t].next = head[u];
	head[u] = t++;

	edge[t].u = v;
	edge[t].v = u;
	edge[t].w = 0;
	edge[t].next = head[v];
	head[v] = t++;
}
void bfs(int start, int endl)//建立到汇点的距离层次图存在dis[]数组中  
{
	int rear = 0, i, j;
	memset(dis, -1, sizeof(dis));
	memset(gap, 0, sizeof(gap));//gap[x]记录dis[i]=x出现了多少次  
	dis[endl] = 0;
	gap[dis[endl]] = 1;
	q[rear++] = endl;
	for (i = 0; i<rear; i++)
	{
		for (j = head[q[i]]; j != -1; j = edge[j].next)
		{
			int v = edge[j].v;
			if (dis[v] == -1)
			{
				++gap[dis[v] = dis[q[i]] + 1];
				q[rear++] = v;
			}
		}
	}
}
int SAP(int start, int endl, int n)
{
	int ans = 0;
	bfs(start, endl);
	int cur[M];//代替head数组  
	memcpy(cur, head, sizeof(head));
	int stack[M], top = 0;//建立手工栈  
	int u = start, i;
	while (dis[start]<n)
	{
		if (u == endl)//当搜到终点时即找到从原点到汇点的增光路,正常处理即可  
		{
			int mini = inf, tep;
			for (i = 0; i<top; i++)
			{
				if (mini>edge[stack[i]].w)
				{
					mini = edge[stack[i]].w;
					tep = i;
				}
			}
			for (i = 0; i<top; i++)
			{
				edge[stack[i]].w -= mini;
				edge[stack[i] ^ 1].w += mini;
			}
			ans += mini;
			top = tep;
			u = edge[stack[top]].u;//此时的u为变容量为0的u  
		}
		if (dis[u] && gap[dis[u] - 1] == 0)//出现了断层,没有增广路  
			break;
		for (i = cur[u]; i != -1; i = edge[i].next)//遍历与u相连的未遍历的节点  
		{
			int v = edge[i].v;
			if (dis[v] != -1)
			{
				if (edge[i].w&&dis[u] == dis[v] + 1)//层次关系找到允许路径  
					break;
			}
		}
		if (i != -1)//找到允许弧  
		{
			cur[u] = i;
			stack[top++] = i;
			u = edge[i].v;
		}
		else//无允许的路径,修改标号 当前点的标号比与之相连的点中最小的多1  
		{
			int mini = n;
			for (i = head[u]; i != -1; i = edge[i].next)
			{
				if (edge[i].w == 0)continue;
				int v = edge[i].v;
				if (mini>dis[v])//找到与u相连的v中dep[v]最小的点  
				{
					mini = dis[v];
					cur[u] = i;//最小标号就是最新的允许弧  
				}
			}
			--gap[dis[u]];//dep[u] 的个数变化了 所以修改gap  
			++gap[dis[u] = mini + 1];//将dep[u]设为min(dep[v]) + 1, 同时修改相应的gap[]  
			if (u != start)//该点非源点&&以u开始的允许弧不存在,退点  
				u = edge[stack[--top]].u;
		}
	}
	return ans;
}
int main()
{
	int n, m;
	while (scanf("%d%d", &m, &n) != -1)
	{
		init();
		while (m--)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			add(a, b, c);
		}
		int ans = SAP(1, n, n);
		printf("%d\n", ans);
	}
}

    拓展建图

        任务建图HDU - 3572 为例)

        INF建图(POJ—1149为例)

        拆点建图(POJ-3281为例)

练习题(HDU - 2732题解)

        未完,待续

    再拓展:

        并查集建图(3081为例)

猜你喜欢

转载自blog.csdn.net/qq_41104612/article/details/80183218
今日推荐