HDU 3549 Flow Problem

版权声明:本人QQ 249712949 欢迎交流算法(请备注)。 https://blog.csdn.net/coord_/article/details/88385176

传送门

基础网络流,这次使用一下dinic算法,BFS+DFS
BFS负责找一个流量可行(仅关注当前边)的层次图,DFS在层次图基础上找增广路,而边上流量的更新在DFS的回溯过程中负责。上述过程重复直到汇点(sink)在BFS层次遍历后不可达。
DFS可以一次只找一条路(在外部循环调用DFS直到返回值为0);也可以一次找多条路,在DFS内部累加flow,下面代码使用后者。
当前弧优化,每次BFS后都要初始化cur[],使得DFS在访问重复点时不重复访问该点的边。首先,这在第一种写法中是显而易见的作用。在第二种写法中,为什么DFS会重复访问点呢(层数为0和1的点在第二种写法中当然不会被重复访问)?不是在BFS中赋层次值时避免了吗?我的答案是:
BFS中没有重复访问点,这没错,但是,某点可能有两个或以上的前驱点是同一层次(都是当前点层次值-1)!而在DFS中仅关心层次是否相邻。
(但事实证明第一种写法优不优化耗时差别明显,第二种写法几乎没差别(但这可能和数据有关))

好了,不扯上面这个问题了,放代码完事(第二种写法)

#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

typedef long long LL;
#define oo 1e9
const int Nmax = 15 + 1;

struct Edge
{
	int f, t, cap, flow;
};
vector<Edge> ve;
vector<int> v[Nmax];
int level[Nmax];                     // BFS,记录层次
int cur[Nmax];                       // DFS,当前弧优化,初始化为0,每次BFS后初始化

void init(int t)
{
	ve.clear();
	for (int i = 1; i <= t; i++)
		v[i].clear();
}

void add_edge(int f, int t, int c)
{
	ve.push_back({ f,t,c,0 });
	ve.push_back({ t,f,0,0 });
	v[f].push_back(ve.size() - 2);
	v[t].push_back(ve.size() - 1);
}

bool bfs(int t)
{
	memset(level, -1, sizeof level);
	queue<int> q;
	q.push(1);
	level[1] = 0;
	for (; !q.empty();)
	{
		int x = q.front();
		q.pop();
		for (int i = 0; i < v[x].size(); i++)
		{
			Edge& e = ve[v[x][i]];
			if (level[e.t] < 0 && e.flow < e.cap)        // 不重复访问
			{
				level[e.t] = level[x] + 1;
				q.push(e.t);
			}
		}
	}
	return level[t] >= 0;
}

int dfs(int n, int t, int f)
{
	if (n == t || f == 0) return f;               // f等于0是因为调用时e.cap==e.flow了
	int flow = 0, f0;
	for (int& i = cur[n]; i < v[n].size(); i++)   // 当前弧优化,i是引用,可间接改变cur[]的值
	{
		Edge& e = ve[v[n][i]];
		if (level[e.t] == level[n] + 1 && (f0 = dfs(e.t, t, min(f, e.cap - e.flow))) > 0)
		{
			e.flow += f0;
			ve[v[n][i] ^ 1].flow -= f0;
			flow += f0;
			f -= f0;                              // 这里f不会变为负值
			if (f == 0) break;
		}
	}
	return flow;
}

int main()
{
	int now = 1;
	int N, M, T;
	scanf("%d", &T);
	for (; T--;)
	{
		int flow = 0;
		scanf("%d%d", &N, &M);
		init(N);
		int f, t, c;
		for (int i = 0; i < M; i++)
		{
			scanf("%d%d%d", &f, &t, &c);
			add_edge(f, t, c);
		}
		for (; bfs(N);)
		{
			memset(cur, 0, sizeof cur);
			flow += dfs(1, N, oo);           // 这里有两种写法,另一种是这里多次调用dfs,而dfs内部不再累加flow,找到一条路后就立即返回
		}
		printf("Case %d: %d\n", now++, flow);
	}
    return 0;
}

// dinic算法
// cin/cout     608ms
// scanf/printf 140ms

第一种写法也放这

#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

typedef long long LL;
#define oo 1e9
const int Nmax = 15 + 1;

struct Edge
{
	int f, t, cap, flow;
};
vector<Edge> ve;
vector<int> v[Nmax];
int level[Nmax];                     // BFS,记录层次
int cur[Nmax];                       // DFS,当前弧优化,初始化为0,每次BFS后初始化

void init(int t)
{
	ve.clear();
	for (int i = 1; i <= t; i++)
		v[i].clear();
}

void add_edge(int f, int t, int c)
{
	ve.push_back({ f,t,c,0 });
	ve.push_back({ t,f,0,0 });
	v[f].push_back(ve.size() - 2);
	v[t].push_back(ve.size() - 1);
}

bool bfs(int t)
{
	memset(level, -1, sizeof level);
	queue<int> q;
	q.push(1);
	level[1] = 0;
	for (; !q.empty();)
	{
		int x = q.front();
		q.pop();
		for (int i = 0; i < v[x].size(); i++)
		{
			Edge& e = ve[v[x][i]];
			if (level[e.t] < 0 && e.flow < e.cap)        // 不重复访问
			{
				level[e.t] = level[x] + 1;
				q.push(e.t);
			}
		}
	}
	return level[t] >= 0;
}

int dfs(int n, int t, int f)
{
	if (n == t || f == 0) return f;               // f等于0是因为调用时e.cap==e.flow了
	int f0;
	for (int& i = cur[n]; i < v[n].size(); i++)   // 当前弧优化,i是引用,可间接改变cur[]的值
	{
		Edge& e = ve[v[n][i]];
		if (level[e.t] == level[n] + 1 && (f0 = dfs(e.t, t, min(f, e.cap - e.flow))) > 0)
		{
			e.flow += f0;
			ve[v[n][i] ^ 1].flow -= f0;
			return f0;                                 //
		}
	}
	return 0;                                          //
}

int main()
{
	int now = 1;
	int N, M, T;
	scanf("%d", &T);
	for (; T--;)
	{
		int flow = 0;
		scanf("%d%d", &N, &M);
		init(N);
		int f, t, c;
		for (int i = 0; i < M; i++)
		{
			scanf("%d%d%d", &f, &t, &c);
			add_edge(f, t, c);
		}
		for (; bfs(N);)
		{
			memset(cur, 0, sizeof cur);
			//flow += dfs(1, N, oo);
			int temp;
			for (; temp = dfs(1, N, oo);)           //
				flow += temp;
		}
		printf("Case %d: %d\n", now++, flow);
	}
	return 0;
}

// dinic算法
// cin/cout     608ms
// scanf/printf 140ms

猜你喜欢

转载自blog.csdn.net/coord_/article/details/88385176
今日推荐