2022.9.29 闲话 😅

😅

涩图:

概述

无权图

无向图可以规约到有向图,所以直接说有向图的存图方法 .

对于每个点 \(u\) 开一个 std::vector,存储 \(u\) 的所有出边 .

写出来大概是这样:

// since C++11
std::vector<int> g[N];
inline void addedge(int u, int v){g[u].emplace_back(v);}
// Tips. 
// 1. 如果只有 C++98 的编译器,将 emplace_back 换成 push_back 即可正常运行
// 2. 极特殊情况可以将 vector 换成 basic_string 来卡常

然后 g[u] 就是 \(u\) 的所有出边组成的 vector 了,可以简单遍历 .

扩展

vector 可以换成任意支持以下操作的容器:

一些例子:std::basic_stringstd::arraystd::dequestd::stackstd::forward_list / std::list / std::slist(G++) .

常用操作

边上维护信息

最常见的一种就是带权图 .

我们存的时候对于每个 g[u] 的出边都绑定一个边权就可以了,类似这样:

// since C++11
typedef std::pair<int, int> pii;
std::vector<pii> g[N];
inline void addedge(int u, int v, int w){g[u].emplace_back(make_pair(v, w));}

对于要维护更多的信息的,比如最小费用最大流,可以考虑把 std::pair 换成手写结构体或 std::tuple .

定位反向边

很多人都以为这个只能链式前向星做吧,于是带重边求桥就只能写链式前向星了?

实际上一条边 \(u\to v\) 完全由起点的编号 \(u\)\(v\)g[u] 中的编号决定 .

于是可以在边上维护反向边的编号信息,这样就可以快速定位反向边了 .

还有一些其他方法:

  • std::unordered_map 存位置 .
  • 用类似 Kruskal 的存边方式存下所有边,然后新开一个 std::vector[] 存边的编号 .

都是差不多的 .

出边信息维护

考虑把 std::vector 换掉,换成平衡树怎么样?

观察一下,发现这样结合 边上维护信息 就可以查询有多少出边不小于 \(k\) 这种询问了 .

当然最平凡的删边也可以 \(O(\log n)\) 完成了,只不过加边也变成 \(O(\log n)\) 了 .

如果说要 \(O(1)\) 做可以用 Hash 表或 std::unordered_set .

换成别的数据结构也差不多,都是一样的 .

实例

可以写一下 std::vector 存图版本的 dinic,一份参考实现:

Dinic 代码实现

LOJ 提交记录

// 点数 N
int n, m, s, t;
struct dinic
{
	static const ll INF = 0x3f3f3f3f3f3f3f3f;
	struct Node
	{
		int u, v; ll w;
		Node(int p, int q, ll r) : u(p), v(q), w(r){}
	};
	vector<int> g[N];
	vector<Node> e;
	inline void addedge(int u, int v, ll w)
	{
		int m = e.size();
		e.emplace_back(Node(u, v, w)); g[u].emplace_back(m);
		e.emplace_back(Node(v, u, 0)); g[v].emplace_back(m+1);
	}
	int cur[N], depth[N];
	inline bool bfs(int s, int t)
	{
		memset(cur, 0, sizeof cur);
		memset(depth, -1, sizeof depth);
		queue<int> q; q.push(s); depth[s] = 0;
		while (!q.empty())
		{
			int u = q.front(); q.pop();
			for (auto ee : g[u])
			{
				int v = e[ee].v;
				if (!~depth[v] && e[ee].w){q.push(v); depth[v] = depth[u] + 1;}
			}
		}
		return ~depth[t];
	}
	ll dfs(int u, int t, ll flow)
	{
		if ((u == t) || (flow <= 0)) return flow;
		ll ans = 0; int _ = g[u].size();
		for (int& p = cur[u]; p < _; p++)
		{
			int ee = g[u][p], v = e[ee].v;
			if (depth[u] + 1 != depth[v]) continue;
			ll nxt = dfs(v, t, min(flow, e[ee].w));
			e[ee].w -= nxt; e[ee ^ 1].w += nxt;
			ans += nxt; flow -= nxt;
			if (flow <= 0) break;
		}
		if (ans <= 0) depth[u] = -1;
		return ans;
	}
	ll maxflow(int s, int t)
	{
		ll ans = 0;
		while (bfs(s, t)) ans += dfs(s, t, INF);
		return ans;
	}
};

😅

posted @ 2022-09-29 19:54  Jijidawang  阅读(113)  评论(5编辑  收藏  举报
😅​