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
可以换成任意支持以下操作的容器:
push_back
,即在最后添加一个元素 .- 可以快速访问所有元素 / 存在一个 老式输出迭代器 (LegacyOutputIterator) .
一些例子:std::basic_string
,std::array
,std::deque
,std::stack
,std::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 代码实现
// 点数 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;
}
};
😅
以下是博客签名,正文无关
本文来自博客园,作者:Jijidawang,转载请注明原文链接:https://www.cnblogs.com/CDOI-24374/p/16739287.html
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0)进行许可。看完如果觉得有用请点个赞吧 QwQ