圖論

ProtectEMmm發表於2024-09-02

圖論

儲存

class C_Graph
{
public:
	struct Edge
	{
		int u, v, w;
		Edge(int _u = 0, int _v = 0, int _w = 0)
		{
			u = _u, v = _v, w = _w;
		}
		friend bool operator<(const Edge& a, const Edge& b)
		{
			return a.w < b.w;
		}
		int operator()(int x)const
		{
			return u ^ v ^ x;
		}
	};
	/*====================*/
	int n;
	vector<Edge>edges;
	vector<vector<int>>edge;
	/*====================*/
	void Init(int n)
	{
		this->n = n; edge.assign(n + 1, vector<int>());
	}
	void AddEdge(int u, int v, int w = 0)
	{
		edges.push_back(Edge(u, v, w));
		edge[u].push_back(edges.size() - 1);
	}
};

2-SAT

namespace _TwoSAT
{
	using namespace _SCC;
	void Init(void)
	{
		for (int i = 1; i <= n; ++i)
		{
			int u = idx[i][1], v = idx[i][0];
			if (belong[u] == belong[v])
			{
				cout << "IMPOSSIBLE" << endl; return;
			}
		}
		cout << "POSSIBLE" << endl;
		for (int i = 1; i <= n; ++i)
		{
			int u = idx[i][1], v = idx[i][0];
			cout << ((belong[u] < belong[v]) ? 1 : 0) << " ";
		}
		cout << endl;
	}
}

尤拉圖

無向圖

namespace _Euler
{
	/*
	預設連通圖,-1不存在,0存在尤拉路徑,1存在尤拉回路
	*/
	const int N = 1e5 + 10;
	/*====================*/
	int degree[N];
	/*====================*/
	int Init(void)
	{
		for (int i = 1; i <= n; ++i)
		{
			degree[i] = G[i].size();
		}
		int cnt = 0;
		for (int i = 1; i <= n; ++i)
		{
			if (degree[i] % 2 == 1)cnt++;
		}
		return cnt == 0 ? 1 : (cnt == 2 ? 0 : -1);
	}
}

有向圖

namespace _Euler
{
	/*
	預設連通圖,-1不存在,0存在尤拉路徑,1存在尤拉回路
	*/
	const int N = 1e5 + 10;
	/*====================*/
	int degree[N];
	/*====================*/
	int Init(void)
	{
		for (int i = 1; i <= n; ++i)
		{
			degree[i] = 0;
		}
		for (int i = 1; i <= m; ++i)
		{
			int u = edge[i].u;
			int v = edge[i].v;
			degree[u]++, degree[v]--;
		}
		int cnt1 = 0, cnt2 = 0, cnt3 = 0;
		for (int i = 1; i <= n; ++i)
		{
			if (degree[i] == -1)cnt1++;
			if (degree[i] == +0)cnt2++;
			if (degree[i] == +1)cnt3++;
		}
		if (cnt1 == 1 && cnt3 == 1 && cnt2 + 2 == n)
		{
			return +0;
		}
		else if (cnt2 == n)
		{
			return +1;
		}
		else
		{
			return -1;
		}
	}
}

最大團

namespace _MaxClique
{
	const int N = 5e1 + 10;
	/*====================*/
	int n; int G[N][N];
	int dp[N], stk[N][N], res;
	/*====================*/
	bool DFS(int ns, int dep)
	{
		if (ns == 0)
		{
			if (dep > res)
			{
				res = dep; return true;
			}
			return false;
		}
		for (int i = 0; i < ns; ++i)
		{
			int u = stk[dep][i], cnt = 0;
			if (dep + dp[u] <= res)return false;
			if (dep + ns - i <= res)return false;
			for (int j = i + 1; j < ns; ++j)
			{
				int v = stk[dep][j];
				if (G[u][v])stk[dep + 1][cnt++] = v;
			}
			if (DFS(cnt, dep + 1))return true;
		}
		return false;
	}
	/*====================*/
	int Init(void)
	{
		cin >> n; res = 0;
		memset(dp, 0, sizeof(dp));
		for (int i = 1; i <= n; ++i)
		{
			for (int j = 1; j <= n; ++j)
			{
				cin >> G[i][j];
			}
		}
		for (int i = n; i >= 1; --i)
		{
			int ns = 0;
			for (int j = i + 1; j <= n; ++j)
			{
				if (G[i][j])stk[1][ns++] = j;
			}
			DFS(ns, 1); dp[i] = res;
		}
		return res;
	}
}

最短路

單源最短路SSSP

SPFA

vector<int> SPFA(C_Graph& G, int s)
{
	vector<int>dis(G.n + 1, INF);
	vector<bool>vis(G.n + 1, false);
	queue<int>q; dis[s] = 0; q.push(s);
	while (!q.empty())
	{
		int cur = q.front(); q.pop(); vis[cur] = false;
		for (auto idx : G.edge[cur])
		{
			int val = G.edges[idx].w;
			int nxt = G.edges[idx](cur);
			if (dis[nxt] > dis[cur] + val)
			{
				dis[nxt] = dis[cur] + val;
				if (!vis[nxt])q.push(nxt), vis[nxt] = true;
			}
		}
	}
	return dis;
}

Dijkstra

class C_Dijkstra
{
public:
	struct Unit
	{
		int v, w;
		Unit(int _v = 0, int _w = 0)
		{
			v = _v, w = _w;
		}
		friend bool operator<(const Unit& a, const Unit& b)
		{
			return a.w > b.w;
		}
	};
	vector<int> operator()(C_Graph& G, int s)
	{
		vector<int>dis(G.n + 1, INF);
		vector<bool>vis(G.n + 1, false);
		priority_queue<Unit>q; q.push(Unit(s, dis[s] = 0));
		while (!q.empty())
		{
			int cur = q.top().v; q.pop();
			if (vis[cur])continue; vis[cur] = true;
			for (auto idx : G.edge[cur])
			{
				int val = G.edges[idx].w;
				int nxt = G.edges[idx](cur);
				if (dis[nxt] > dis[cur] + val)
				{
					dis[nxt] = dis[cur] + val;
					q.push(Unit(nxt, dis[nxt]));
				}
			}
		}
		return dis;
	}
};

SPFA-SLF

vector<int> SPFA(C_Graph& G, int s)
{
	vector<int>dis(G.n + 1, INF);
	vector<bool>vis(G.n + 1, false);
	deque<int>q; dis[s] = 0; q.push_back(s);
	while (!q.empty())
	{
		int cur = q.front(); q.pop_front(); vis[cur] = false;
		if (!q.empty() && dis[q.front()] > dis[q.back()])
		{
			swap(q.front(), q.back());
		}
		for (auto idx : G.edge[cur])
		{
			int val = G.edges[idx].w;
			int nxt = G.edges[idx](cur);
			if (dis[nxt] > dis[cur] + val)
			{
				dis[nxt] = dis[cur] + val;
				if (!vis[nxt])
				{
					vis[nxt] = true;
					if (!q.empty() && dis[nxt] < dis[q.front()])
					{
						q.push_front(nxt);
					}
					else
					{
						q.push_back(nxt);
					}
				}
			}
		}
	}
	return dis;
}

全源最短路APSP

Floyd

vector<vector<int>> Floyd(C_Graph& G)
{
	vector<vector<int>>dis(G.n + 1, vector<int>(G.n + 1, INF));
	for (int u = 1; u <= G.n; ++u)
	{
		dis[u][u] = 0;
		for (auto idx : G.edge[u])
		{
			int v = G.edges[idx](u);
			int w = G.edges[idx].w;
			dis[u][v] = min(dis[u][v], w);
		}
	}
	for (int k = 1; k <= G.n; ++k)
	{
		for (int i = 1; i <= G.n; ++i)
		{
			for (int j = 1; j <= G.n; ++j)
			{
				dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
			}
		}
	}
	return dis;
}

Johnson


環相關

有向圖判環

bool Loop(C_Graph& G)
{
	queue<int>q; int cnt = 0;
	vector<int>indegree(G.n + 1, 0);
	for (int i = 0; i < G.edges.size(); ++i)
	{
		indegree[G.edges[i].v]++;
	}
	for (int i = 1; i <= G.n; ++i)
	{
		if (indegree[i] == 0)q.push(i);
	}
	while (!q.empty())
	{
		int cur = q.front(); q.pop(); cnt++;
		for (auto idx : G.edge[cur])
		{
			int nxt = G.edges[idx](cur);
			if (--indegree[nxt] == 0)q.push(nxt);
		}
	}
	return cnt != G.n;
}

任意圖判負環

bool Loop(C_Graph& G)
{
	vector<int>cnt(G.n + 1, 0);
	vector<int>dis(G.n + 1, 0);
	vector<bool>vis(G.n + 1, false);
	/*====================*/
	queue<int>q; 
	for (int i = 1; i <= G.n; ++i)
	{
		q.push(i); vis[i] = true;
	}
	while (!q.empty())
	{
		int cur = q.front(); q.pop(); vis[cur] = false;
		for (auto idx : G.edge[cur])
		{
			int val = G.edges[idx].w;
			int nxt = G.edges[idx](cur);
			if (dis[nxt] > dis[cur] + val)
			{
				cnt[nxt] = cnt[cur] + 1;
				dis[nxt] = dis[cur] + val;
				if (cnt[nxt] >= G.n)return true;
				if (!vis[nxt])q.push(nxt), vis[nxt] = true;
			}
		}
	}
	return false;
}

無向圖求最小環

int Loop(C_Graph& G)
{
	vector<vector<int>>mindis(G.n + 1, vector<int>(G.n + 1, INF));
	for (int u = 1; u <= G.n; ++u)
	{
		mindis[u][u] = 0;
		for (auto idx : G.edge[u])
		{
			int v = G.edges[idx](u);
			int w = G.edges[idx].w;
			mindis[u][v] = min(mindis[u][v], w);
		}
	}
	auto dis = mindis; int res = INF;
	for (int k = 1; k <= G.n; ++k)
	{
		for (int i = 1; i < k; ++i)
		{
			for (int j = i + 1; j < k; ++j)
			{
				if (mindis[i][j] != INF)
				{
					res = min(res, mindis[i][j] + dis[i][k] + dis[k][j]);
				}
			}
		}
		for (int i = 1; i <= G.n; ++i)
		{
			for (int j = 1; j <= G.n; ++j)
			{
				mindis[i][j] = min(mindis[i][j], mindis[i][k] + mindis[k][j]);
			}
		}
	}
	return res;
}

有向圖求最小環

int Loop(C_Graph& G)
{
	vector<vector<int>>inedge(G.n + 1, vector<int>());
	for (int i = 0; i < G.edges.size(); ++i)
	{
		inedge[G.edges[i].v].push_back(i);
	}
	int res = INF;
	for (int v = 1; v <= G.n; ++v)
	{
		vector<int>dis = Dijkstra(G, v);
		for (auto idx : inedge[v])
		{
			res = min(res, dis[G.edges[idx](v)] + G.edges[idx].w);
		}
	}
	return res;
}

無向圖三元環計數

int Loop(C_Graph& G)
{
	vector<int>tag(G.n + 1, 0);
	vector<int>degree(G.n + 1, 0);
	vector<vector<int>>out(G.n + 1, vector<int>());
	for (auto& e : G.edges)
	{
		degree[e.u]++, degree[e.v]++;
	}
	for (auto& e : G.edges)
	{
		int u = e.u, v = e.v;
		if (degree[u] == degree[v] && u > v)swap(u, v);
		if (degree[u] != degree[v] && degree[u] > degree[v])swap(u, v);
		out[u].push_back(v);
	}
	int res = 0;
	for (int u = 1; u <= G.n; ++u)
	{
		for (auto v : out[u])
		{
			tag[v] = u;
		}
		for (auto v : out[u])
		{
			for (auto w : out[v])
			{
				res += (tag[w] == u);
			}
		}
	}
	return res;
}

網路流

最大流

ISAP

namespace _ISAP
{
	const int N = 1e5 + 10;
	const int M = 1e5 + 10;
	/*====================*/
	const int INF = 0X7FFFFFFF;
	/*====================*/
	struct Edge
	{
		int u, v, c, f;
		Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
		{
			u = _u, v = _v, c = _c, f = _f;
		}
	};
	/*====================*/
	int pre[N];//路徑前驅
	int cur[N];//當前弧最佳化
	int n, m, s, t;//點,邊,源,匯
	vector<int>G[N];//鄰接表
	int d[N], vis[N], num[N];//圖分層
	Edge edge[2 * M]; int cnt;//邊
	/*====================*/
	void AddEdge(int u, int v, int c)
	{
		edge[cnt++] = Edge(u, v, c, 0);
		edge[cnt++] = Edge(v, u, 0, 0);
		G[u].push_back(cnt - 2);
		G[v].push_back(cnt - 1);
	}
	/*====================*/
	void BFS(void)
	{
		for (int i = 0; i <= n; ++i)
		{
			d[i] = vis[i] = num[i] = 0;
		}
		queue<int>q; q.push(t);
		d[t] = 0; vis[t] = 1;
		while (!q.empty())
		{
			int x = q.front(); q.pop();
			for (int i = 0; i < G[x].size(); ++i)
			{
				Edge& e = edge[G[x][i]];
				if (!vis[e.u] && e.c > e.f)
				{
					vis[e.u] = 1; d[e.u] = d[x] + 1; q.push(e.u);
				}
			}
		}
		for (int i = 0; i < n; ++i)num[d[i]]++;
	}
	int Augumemt(void)
	{
		int x, k = INF;
		x = t; while (x != s)
		{
			Edge& e = edge[pre[x]];
			k = min(k, e.c - e.f);
			x = edge[pre[x]].u;
		}
		x = t; while (x != s)
		{
			edge[pre[x]].f += k;
			edge[pre[x] ^ 1].f -= k;
			x = edge[pre[x]].u;
		}
		return k;
	}
	int MaxFlow(void)
	{
		for (int i = 1; i <= n; ++i)
		{
			pre[i] = cur[i] = 0;
		}

		BFS(); int x = s, flow = 0;
		
		while (d[s] < n)
		{
			if (x == t)
			{
				flow += Augumemt(); x = s;
			}
			int flag = 0;
			for (int& i = cur[x]; i < G[x].size(); ++i)
			{
				Edge& e = edge[G[x][i]];
				if (e.c > e.f && d[x] == d[e.v] + 1)
				{
					flag = 1; pre[e.v] = G[x][i]; x = e.v; break;
				}
			}
			if (!flag)
			{
				int l = n - 1;
				for (int i = 0; i < G[x].size(); ++i)
				{
					Edge& e = edge[G[x][i]];
					if (e.c > e.f)l = min(l, d[e.v]);
				}
				if (--num[d[x]] == 0)break;
				num[d[x] = l + 1]++; cur[x] = 0;
				if (x != s)x = edge[pre[x]].u;
			}
		}
		return flow;
	}
	/*====================*/
	int Init(void)
	{
		cnt = 0;
		cin >> n >> m >> s >> t;
		for (int i = 1; i <= n; ++i)
		{
			G[i].clear();
		}
		for (int i = 1; i <= m; ++i)
		{
			int u, v, c;
			cin >> u >> v >> c;
			AddEdge(u, v, c);
		}
		return MaxFlow();
	}
};

HLPP

namespace _HLPP
{
	const int N = 1e5 + 10;
	const int M = 1e5 + 10;
	/*====================*/
	const int INF = 0X7FFFFFFF;
	/*====================*/
	struct Edge
	{
		int next, v, c;
		Edge(int _next = 0, int _v = 0, int _c = 0)
		{
			next = _next, v = _v, c = _c;
		}
	};
	/*====================*/
	int n, m, s, t;
	int d[N], num[N];
	stack<int> lib[N];
	int ex[N], level = 0;
	Edge edge[2 * M]; int head[N], cnt;
	/*====================*/
	void AddEdge(int u, int v, int c) 
	{
		edge[cnt] = Edge(head[u], v, c), head[u] = cnt++;
		edge[cnt] = Edge(head[v], u, 0), head[v] = cnt++;
	}
	/*====================*/
	int Push(int u) 
	{
		bool init = u == s;
		for (int i = head[u]; i != -1; i = edge[i].next)
		{
			const int& v = edge[i].v, & c = edge[i].c;
			if (!c || init == false && d[u] != d[v] + 1)continue;
			int k = init ? c : min(c, ex[u]);
			if (v != s && v != t && !ex[v]) lib[d[v]].push(v), level = max(level, d[v]);
			ex[u] -= k, ex[v] += k, edge[i].c -= k, edge[i ^ 1].c += k;
			if (!ex[u]) return 0;
		}
		return 1;
	}
	void Relabel(int x) 
	{
		d[x] = INF;
		for (int i = head[x]; i != -1; i = edge[i].next)
		{
			if (edge[i].c) d[x] = min(d[x], d[edge[i].v]);
		}
		if (++d[x] < n) 
		{  
			lib[d[x]].push(x); level = max(level, d[x]); ++num[d[x]];
		}
	}
	bool BFS(void)
	{
		for (int i = 1; i <= n; ++i)
		{
			d[i] = INF; num[i] = 0;
		}
		queue<int>q; q.push(t), d[t] = 0;
		while (!q.empty()) 
		{
			int u = q.front(); q.pop(); num[d[u]]++;
			for (int i = head[u]; i!=-1; i = edge[i].next) 
			{
				const int& v = edge[i].v;
				if (edge[i ^ 1].c && d[v] > d[u] + 1) d[v] = d[u] + 1, q.push(v);
			}
		}
		return d[s] != INF;
	}
	int Select(void) 
	{
		while (lib[level].size() == 0 && level > -1) level--;
		return level == -1 ? 0 : lib[level].top();
	}
	int MaxFlow(void) 
	{
		if (!BFS()) return 0;
		d[s] = n; Push(s); int x;
		while (x = Select())
		{
			lib[level].pop();
			if (Push(x)) 
			{
				if (!--num[d[x]])
				{
					for (int i = 1; i <= n; ++i)
					{
						if (i != s && i != t && d[i] > d[x] && d[i] < n + 1)
						{
							d[i] = n + 1;
						}
					}
				}
				Relabel(x);
			}
		}
		return ex[t];
	}
	/*====================*/
	int Init(void)
	{
		cnt = 0;
		cin >> n >> m >> s >> t;
		memset(head, -1, sizeof(head));
		for (int i = 1; i <= m; ++i)
		{
			int u, v, c;
			cin >> u >> v >> c;
			AddEdge(u, v, c);
		}
		return MaxFlow();
	}
}

Dinic

/*
* 使用方法
* 1.建立物件
* 2.呼叫AddVertex()建立點
* 3.呼叫Init()初始化大小
* 4.呼叫AddEdge()建立邊
* 5.呼叫MaxFlow()獲取最大流
*/
class C_Dinic
{
public:
	static const int INF = 0X7FFFFFFF;
	/*====================*/
	struct Edge
	{
		int u, v, c, f;
		Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
		{
			u = _u, v = _v, c = _c, f = _f;
		}
	};
	/*====================*/
	int n, s, t;
	/*====================*/
	vector<Edge>edge;
	vector<vector<int>>G;
	/*====================*/
	C_Dinic(void)
	{
		n = 2, s = 1, t = 2;
	}
private:
	vector<int>cur;//當前弧最佳化
	vector<int>d, vis;//圖分層
	/*====================*/
	bool BFS(void)
	{
		fill(d.begin(), d.end(), 0);
		fill(vis.begin(), vis.end(), 0);
		d[s] = 0; vis[s] = 1;
		queue<int>q; q.push(s);
		while (!q.empty())
		{
			int x = q.front(); q.pop();
			for (int i = 0; i < G[x].size(); ++i)
			{
				Edge& e = edge[G[x][i]];
				if (!vis[e.v] && e.c > e.f)
				{
					vis[e.v] = 1; d[e.v] = d[x] + 1; q.push(e.v);
				}
			}
		}
		return vis[t];
	}
	int DFS(int x, int k)
	{
		int flow = 0, f;
		if (x == t || k == 0) return k;
		for (int& i = cur[x]; i < G[x].size(); ++i)
		{
			Edge& e = edge[G[x][i]];
			if (d[x] + 1 == d[e.v] && (f = DFS(e.v, min(k, e.c - e.f))) > 0)
			{
				e.f += f; edge[G[x][i] ^ 1].f -= f;
				flow += f; k -= f; if (k == 0) break;
			}
		}
		return flow;
	}
public:
	int S(void) { return s; }
	int T(void) { return t; }
	/*====================*/
	int AddVertex(void)
	{
		return ++n;
	}
	int AddEdge(int u, int v, int c)
	{
		edge.push_back(Edge(u, v, c, 0));
		edge.push_back(Edge(v, u, 0, 0));
		G[u].push_back(edge.size() - 2);
		G[v].push_back(edge.size() - 1);
		return edge.size() - 2;
	}
	/*====================*/
	void Init(void)
	{
		d.assign(n + 1, int());
		vis.assign(n + 1, int());
		cur.assign(n + 1, int());
		G.assign(n + 1, vector<int>());
	}
	/*====================*/
	int MaxFlow(void)
	{
		int flow = 0;
		while (BFS())
		{
			flow += DFS(s, INF);
			fill(cur.begin(), cur.end(), 0);
		}
		return flow;
	}
};

Dinic-Scaling

namespace _Dinic
{
	const int N = 1e5 + 10;
	const int M = 1e5 + 10;
	/*====================*/
	const int INF = 0X7FFFFFFF;
	/*====================*/
	struct Edge
	{
		int u, v, c, f;
		Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
		{
			u = _u, v = _v, c = _c, f = _f;
		}
		friend bool operator<(const Edge& a, const Edge& b)
		{
			return a.c > b.c;
		}
	};
	/*====================*/
	int d[N];//圖分層
	int cur[N];//當前弧最佳化
	Edge _edge[M];//即將加入流網路的邊
	int n, m, s, t;//點,邊,源,匯
	vector<int>G[N];//鄰接表
	Edge edge[2 * M]; int cnt;//邊
	/*====================*/
	void AddEdge(int u, int v, int c)
	{
		edge[cnt++] = Edge(u, v, c, 0);
		edge[cnt++] = Edge(v, u, 0, 0);
		G[u].push_back(cnt - 2);
	}
	/*====================*/
	bool BFS(void)
	{
		for (int i = 0; i <= n; ++i)
		{
			d[i] = INF;
		}
		queue<int>q; q.push(s); d[s] = 0;
		while (!q.empty())
		{
			int x = q.front(); q.pop();
			for (int i = 0; i < G[x].size(); ++i)
			{
				Edge& e = edge[G[x][i]];
				if (d[e.v] >= INF && e.c > e.f)
				{
					d[e.v] = d[x] + 1; q.push(e.v);
				}
			}
		}
		return d[t] < INF;
	}
	int DFS(int x, int k)
	{
		int flow = 0, f;
		if (x == t || k == 0) return k;
		for (int& i = cur[x]; i < G[x].size(); ++i)
		{
			Edge& e = edge[G[x][i]];
			if (d[x] + 1 == d[e.v] && (f = DFS(e.v, min(k, e.c - e.f))) > 0)
			{
				e.f += f; edge[G[x][i] ^ 1].f -= f;
				flow += f; k -= f; if (k == 0) break;
			}
		}
		return flow;
	}
	int Dinic(void)
	{
		int flow = 0;
		while (BFS())
		{
			flow += DFS(s, INF);
			for (int i = 1; i <= n; ++i)
			{
				cur[i] = 0;
			}
		}
		return flow;
	}
	int MaxFlow(void)
	{
		int flow = 0;
		sort(_edge, _edge + m);
		for (int type : {0, 1})
		{
			for (int p = 1 << 30, i = 0; p; p /= 2)
			{
				while (i < m && _edge[i].c >= p)
				{
					if (type == 0)AddEdge(_edge[i].u, _edge[i].v, _edge[i].c);
					if (type == 1)G[_edge[i].v].push_back(i * 2 + 1); i++;
				}
				flow += Dinic();
			}
		}
		return flow;
	}
	/*====================*/
	int Init(void)
	{
		cnt = 0;
		cin >> n >> m >> s >> t;
		for (int i = 1; i <= n; ++i)
		{
			G[i].clear();
		}
		for (int i = 0; i < m; ++i)
		{
			int u, v, c;
			cin >> u >> v >> c;
			_edge[i] = Edge(u, v, c);
		}
		return MaxFlow();
	}
}

Dinic-最後反悔

/*
* 使用方法
* 1.建立物件
* 2.呼叫AddVertex()建立點
* 3.呼叫Init()初始化大小
* 4.呼叫AddEdge()建立邊
* 5.呼叫MaxFlow()獲取最大流
*/
class C_Dinic
{
public:
	static const int INF = 0X7FFFFFFF;
	/*====================*/
	struct Edge
	{
		int u, v, c, f;
		Edge(int _u = 0, int _v = 0, int _c = 0, int _f = 0)
		{
			u = _u, v = _v, c = _c, f = _f;
		}
	};
	/*====================*/
	int n = 2, s = 1, t = 2;
	/*====================*/
	vector<Edge>edge;
	vector<vector<int>>G1;
	vector<vector<int>>G2;
private:
	vector<int>cur;//當前弧最佳化
	vector<int>d, vis;//圖分層
	/*====================*/
	bool BFS(void)
	{
		fill(d.begin(), d.end(), 0);
		fill(vis.begin(), vis.end(), 0);
		d[s] = 0; vis[s] = 1;
		queue<int>q; q.push(s);
		while (!q.empty())
		{
			int x = q.front(); q.pop();
			for (int i = 0; i < G1[x].size(); ++i)
			{
				Edge& e = edge[G1[x][i]];
				if (!vis[e.v] && e.c > e.f)
				{
					vis[e.v] = 1; d[e.v] = d[x] + 1; q.push(e.v);
				}
			}
		}
		return vis[t];
	}
	int DFS(int x, int k)
	{
		int flow = 0, f;
		if (x == t || k == 0) return k;
		for (int& i = cur[x]; i < G1[x].size(); ++i)
		{
			Edge& e = edge[G1[x][i]];
			if (d[x] + 1 == d[e.v] && (f = DFS(e.v, min(k, e.c - e.f))) > 0)
			{
				e.f += f; edge[G1[x][i] ^ 1].f -= f;
				flow += f; k -= f; if (k == 0) break;
			}
		}
		return flow;
	}
public:
	int S(void) { return s; }
	int T(void) { return t; }
	/*====================*/
	int AddVertex(void)
	{
		return ++n;
	}
	int AddEdge(int u, int v, int c)
	{
		edge.push_back(Edge(u, v, c, 0));
		edge.push_back(Edge(v, u, 0, 0));
		G1[u].push_back(edge.size() - 2);
		G2[v].push_back(edge.size() - 1);
		return edge.size() - 2;
	}
	/*====================*/
	void Init(void)
	{
		d.assign(n + 1, int());
		vis.assign(n + 1, int());
		cur.assign(n + 1, int());
		G1.assign(n + 1, vector<int>());
		G2.assign(n + 1, vector<int>());
	}
	/*====================*/
	int MaxFlow(void)
	{
		int flow = 0;
		while (BFS())
		{
			flow += DFS(s, INF);
			fill(cur.begin(), cur.end(), 0);
		}
		for (int i = 1; i <= n; ++i)
		{
			for (auto idx : G2[i])
			{
				G1[i].push_back(idx);
			}
		}
		while (BFS())
		{
			flow += DFS(s, INF);
			fill(cur.begin(), cur.end(), 0);
		}
		return flow;
	}
};

費用流

EK

namespace _EK
{
	const int N = 1e5 + 10;
	const int M = 1e5 + 10;
	/*====================*/
	const int INF = 0X3F3F3F3F;
	/*====================*/
	struct Edge
	{
		int next, v, c, w;
		Edge(int _next = 0, int _v = 0, int _c = 0, int _w = 0)
		{
			next = _next, v = _v, c = _c, w = _w;
		}
	};
	/*====================*/
	int n, m, s, t;
	int maxflow, mincost;
	Edge edge[2 * M]; int head[N], cnt;
	int dis[N], pre[N], incf[N]; bool vis[N];
	/*====================*/
	void AddEdge(int u, int v, int c, int w)
	{
		edge[cnt] = Edge(head[u], v, c, +w); head[u] = cnt++;
		edge[cnt] = Edge(head[v], u, 0, -w); head[v] = cnt++;
	}
	/*====================*/
	bool SPFA(void)
	{
		memset(dis, 0X3F, sizeof(dis));
		queue<int> q; q.push(s);
		dis[s] = 0, incf[s] = INF, incf[t] = 0;
		while (!q.empty())
		{
			int u = q.front(); q.pop(); vis[u] = false;
			for (int i = head[u]; i != -1; i = edge[i].next)
			{
				int v = edge[i].v, c = edge[i].c, w = edge[i].w;
				if (!c || dis[v] <= dis[u] + w) continue;
				dis[v] = dis[u] + w, incf[v] = min(c, incf[u]), pre[v] = i;
				if (!vis[v])q.push(v), vis[v] = true;
			}
		}
		return incf[t];
	}
	int MinCost(void)
	{
		while (SPFA())
		{
			maxflow += incf[t];
			for (int u = t; u != s; u = edge[pre[u] ^ 1].v)
			{
				edge[pre[u]].c -= incf[t];
				edge[pre[u] ^ 1].c += incf[t];
				mincost += incf[t] * edge[pre[u]].w;
			}
		}
		return mincost;
	}
	/*====================*/
	int Init(void)
	{
		cin >> n >> m >> s >> t;
		mincost = maxflow = cnt = 0;
		memset(head, -1, sizeof(head));
		for (int i = 1; i <= m; ++i)
		{
			int u, v, c, w;
			cin >> u >> v >> c >> w;
			AddEdge(u, v, c, w);
		}
		return MinCost();
	}
}

ZKW費用流

/*
* 使用方法
* 1.建立物件
* 2.呼叫AddVertex()建立點
* 3.呼叫Init()初始化大小
* 4.呼叫AddEdge()建立邊
* 5.呼叫MinCost()獲取最小費用
*/
class C_ZKW
{
public:
	static const int INF = 0X7FFFFFFF;
	/*====================*/
	struct Edge
	{
		int u, v, c, w;
		Edge(int _u = 0, int _v = 0, int _c = 0, int _w = 0)
		{
			u = _u, v = _v, c = _c, w = _w;
		}
	};
	/*====================*/
	int n = 2, s = 1, t = 2;
	/*====================*/
	vector<Edge>edge;
	vector<vector<int>>G;
	int mincost, maxflow;
private:
	vector<int>dis;
	vector<bool>vis;
	/*====================*/
	bool SPFA(void)
	{
		fill(vis.begin(), vis.end(), false);
		fill(dis.begin(), dis.end(), INF);
		vis[t] = true, dis[t] = 0;
		deque<int> q; q.push_back(t);
		while (!q.empty())
		{
			int x = q.front(); q.pop_front(), vis[x] = false;
			if (!q.empty() && dis[q.front()] > dis[q.back()])
			{
				swap(q.front(), q.back());
			}
			for (int i = 0; i < G[x].size(); ++i)
			{
				Edge& e1 = edge[G[x][i] ^ 0];
				Edge& e2 = edge[G[x][i] ^ 1];
				if (e2.c != 0 && dis[e1.v] > dis[x] - e1.w)
				{
					dis[e1.v] = dis[x] - e1.w;
					if (!vis[e1.v])
					{
						vis[e1.v] = true;
						if (!q.empty() && dis[e1.v] < dis[q.front()])
						{
							q.push_front(e1.v);
						}
						else
						{
							q.push_back(e1.v);
						}
					}
				}
			}
		}
		return dis[s] < INF;
	}
	int DFS(int x, int k)
	{
		vis[x] = true; int flow = 0, f;
		if (x == t || k == 0) return k;
		for (int i = 0; i < G[x].size(); ++i)
		{
			Edge& e1 = edge[G[x][i] ^ 0];
			Edge& e2 = edge[G[x][i] ^ 1];
			if (vis[e1.v] || e1.c == 0)continue;
			if (dis[x] - e1.w == dis[e1.v] && (f = DFS(e1.v, min(k, e1.c))) > 0)
			{
				e1.c -= f, e2.c += f; flow += f, k -= f;
				mincost += f * e1.w; if (k == 0) break;
			}
		}
		return flow;
	}
public:
	int S(void) { return s; }
	int T(void) { return t; }
	/*====================*/
	int AddVertex(void)
	{
		return ++n;
	}
	int AddEdge(int u, int v, int c, int w)
	{
		edge.push_back(Edge(u, v, c, +w));
		edge.push_back(Edge(v, u, 0, -w));
		G[u].push_back(edge.size() - 2);
		G[v].push_back(edge.size() - 1);
		return edge.size() - 2;
	}
	/*====================*/
	void Init(void)
	{
		dis.assign(n + 1, int());
		vis.assign(n + 1, int());
		G.assign(n + 1, vector<int>());
	}
	/*====================*/
	int MinCost(void)
	{
		maxflow = mincost = 0;
		while (SPFA())
		{
			vis[t] = true;
			while (vis[t])
			{
				fill(vis.begin(), vis.end(), false);
				maxflow += DFS(s, INF);
			}
		}
		return mincost;
	}
};

支配樹

namespace Lengauer_Tarjan
{
	struct Edge
	{
		int v, x;
		Edge(int _v = 0, int _x = 0)
		{
			v = _v, x = _x;
		}
	};
	/*====================*/
	int n, m;
	Edge edge[M * 3]; int head[3][N], tot;
	int idx[N], dfn[N], dfc;
	int fa[N], fth[N], mn[N], idm[N], sdm[N];
	/*====================*/
	void Add(int x, int u, int v)
	{
		edge[head[x][u] = ++tot] = Edge(v, head[x][u]);
	}
	void Add(int u, int v)
	{
		Add(0, u, v); Add(1, v, u);
	}
	void DFS(int u)
	{
		idx[dfn[u] = ++dfc] = u;
		for (int i = head[0][u]; i; i = edge[i].x)
		{
			int v = edge[i].v;
			if (!dfn[v])
			{
				DFS(v), fth[v] = u;
			}
		}
	}
	int Find(int x)
	{
		if (fa[x] == x)
		{
			return x;
		}
		int tmp = fa[x];
		fa[x] = Find(fa[x]);
		if (dfn[sdm[mn[tmp]]] < dfn[sdm[mn[x]]])
		{
			mn[x] = mn[tmp];
		}
		return fa[x];
	}
	void Tarjan(int st)
	{
		DFS(st);
		for (int i = 1; i <= n; ++i)
		{
			fa[i] = sdm[i] = mn[i] = i;
		}
		for (int i = dfc; i >= 2; --i)
		{
			int u = idx[i], res = INF;
			for (int j = head[1][u]; j; j = edge[j].x)
			{
				int v = edge[j].v; Find(v);
				if (dfn[v] < dfn[u])
				{
					res = min(res, dfn[v]);
				}
				else
				{
					res = min(res, dfn[sdm[mn[v]]]);
				}
			}
			sdm[u] = idx[res];
			fa[u] = fth[u];
			Add(2, sdm[u], u);
			u = fth[u];
			for (int j = head[2][u]; j; j = edge[j].x)
			{
				int v = edge[j].v; Find(v);
				if (sdm[mn[v]] == u)
				{
					idm[v] = u;
				}
				else
				{
					idm[v] = mn[v];
				}
			}
			head[2][u] = 0;
		}
		for (int i = 2; i <= dfc; ++i)
		{
			int u = idx[i];
			if (idm[u] != sdm[u])
			{
				idm[u] = idm[idm[u]];
			}
		}
	}
	/*====================*/
	void Init(int s)
	{
		Tarjan(s);
		tot = dfc = 0;
		for (int i = 1; i <= n; ++i)
		{
			dfn[i] = head[0][i] = head[1][i] = head[2][i] = 0;
		}
	}
	//樹上連邊idm[i] -> i;
}

拓撲排序

void TopSort(C_Graph& G)
{
	vector<int>indegree(G.n + 1, 0); queue<int>q;
	for (const auto& edge : G.edge)indegree[edge.v]++;
	for (int i = 1; i <= G.n; ++i)if (indegree[i] == 0)q.push(i);
	while (!q.empty())
	{
		int cur = q.front(); q.pop(); cout << cur << " ";
		for (int i = 0; i < G[cur].size(); ++i)
		{
			int nxt = G(G[cur][i]).node(cur);
			if (--indegree[nxt] == 0)q.push(nxt);
		}
	}
}

差分約束

namespace _SDC
{
    /*
    存在負環時無解
    記得建立一個超級源點
    A-B<=W的不等式,由B->A,邊權為W
    跑最短路時為最大差值,跑最長路時為最小差值
    */
    const int N = 1e5 + 10;
	/*====================*/
	const int INF = 0X3F3F3F3F;
	/*====================*/
	int dis[N]; int cnt[N]; bool vis[N];
	/*====================*/
	bool Init(void)
	{
		G[0].clear(); cnt[0] = 0;
		for (int i = 1; i <= n; ++i)
		{
			G[0].push_back(++m);
			edge[m] = Edge(0, i, 0);
			dis[i] = INF, vis[i] = false, cnt[i] = 0;
		}
		queue<int>q; dis[0] = 0; q.push(0);
		while (!q.empty())
		{
			int cur = q.front(); q.pop(); vis[cur] = false;
			for (int i = 0; i < G[cur].size(); ++i)
			{
				int val = edge[G[cur][i]].w;
				int nxt = edge[G[cur][i]].node(cur);
				if (dis[nxt] > dis[cur] + val)
				{
					cnt[nxt] = cnt[cur] + 1;
					dis[nxt] = dis[cur] + val;
					if (cnt[nxt] > n)return false;
					if (!vis[nxt])
					{
						q.push(nxt); vis[nxt] = true;
					}
				}
			}
		}
		return true;
	}
}

圖的連通性

雙連通分量

邊雙連通分量

namespace _E_DCC
{
	const int N = 1e5 + 10;
	/*====================*/
	int belong[N], cnt;
	int dfn[N], low[N], num;
	/*====================*/
	void Tarjan(int cur, int in_edge)
	{
		dfn[cur] = low[cur] = ++num;
		for (int i = 0; i < G[cur].size(); ++i)
		{
			int nxt = edge[G[cur][i]].node(cur);
			if (!dfn[nxt])
			{
				Tarjan(nxt, G[cur][i]);
				low[cur] = min(low[cur], low[nxt]);
				if (low[nxt] > dfn[cur])
				{
					edge[G[cur][i]].bridge = true;
				}
			}
			else if (i != in_edge)
			{
				low[cur] = min(low[cur], dfn[nxt]);
			}
		}
	}
	void DFS(int cur)
	{
		belong[cur] = cnt;
		for (int i = 0; i < G[cur].size(); ++i)
		{
			int nxt = edge[G[cur][i]].node(cur);
			if (edge[G[cur][i]].bridge)continue;
			if (belong[nxt])continue; DFS(nxt);
		}
	}
	/*====================*/
	void Init(void)
	{
		for (int i = 1; i <= n; ++i)
		{
			if (!dfn[i])Tarjan(i, 0);
		}
		for (int i = 1; i <= n; ++i)
		{
			if (!belong[i])cnt++, DFS(i);
		}
	}
}

點雙連通分量

namespace _V_DCC
{
	const int N = 1e5 + 10;
	/*====================*/
	vector<int>dcc[N];
	bool cut[N]; int cnt;
	stack<int>lib; int root;
	int dfn[N], low[N], num;
	/*====================*/
	void Tarjan(int cur)
	{
		int flag = 0; lib.push(cur);
		dfn[cur] = low[cur] = ++num;
		if (cur == root && G[cur].size() == 0)
		{
			dcc[++cnt].push_back(cur); return;
		}
		for (int i = 0; i < G[cur].size(); ++i)
		{
			int nxt = edge[G[cur][i]].node(cur);
			if (!dfn[nxt])
			{
				Tarjan(nxt);
				low[cur] = min(low[cur], low[nxt]);
				if (low[nxt] >= dfn[cur])
				{
					flag++; cnt++; int top;
					if (cur != root || flag > 1)
					{
						cut[cur] = true;
					}
					do
					{
						top = lib.top(); lib.pop();
						dcc[cnt].push_back(top);
					} while (top != nxt);
					dcc[cnt].push_back(cur);
				}
			}
			else
			{
				low[cur] = min(low[cur], dfn[nxt]);
			}
		}
	}
	/*====================*/
	void Init(void)
	{
		for (int i = 1; i <= n; ++i)
		{
			if (!dfn[i])Tarjan(root = i);
		}
	}
}

獲取點雙內部的邊

void Tarjan(int cur, int e)
{
	dfn[cur] = low[cur] = ++num;
	if (cur != root || G[cur].size() != 0)
	{
		for (int i = 0; i < G[cur].size(); ++i)
		{
			int nxt = edge[G[cur][i]].node(cur);
			if (!dfn[nxt])
			{
				lib.push(G[cur][i]); Tarjan(nxt, G[cur][i]);
				low[cur] = min(low[cur], low[nxt]);
				if (low[nxt] >= dfn[cur])
				{
					cnt++; int top;
					do
					{
						top = lib.top(); lib.pop();
						dcc[cnt].push_back(edge[top].w);
					} while (top != G[cur][i]);
				}
			}
			else
			{
				if (dfn[nxt] < dfn[cur] && G[cur][i] != e)
				{
					lib.push(G[cur][i]);
				}
				low[cur] = min(low[cur], dfn[nxt]);
			}
		}
	}
}

強連通分量

namespace _SCC
{
	const int N = 1e5 + 10;
	/*====================*/
	int belong[N];
	int dfn[N], low[N], num;
	stack<int>lib; int ins[N];
	vector<int>scc[N]; int cnt;
	/*====================*/
	void Tarjan(int cur)
	{
		lib.push(cur); ins[cur] = 1;
		dfn[cur] = low[cur] = ++num;
		for (int i = 0; i < G[cur].size(); ++i)
		{
			int nxt = edge[G[cur][i]].node(cur);
			if (!dfn[nxt])
			{
				Tarjan(nxt);
				low[cur] = min(low[cur], low[nxt]);
			}
			else if (ins[nxt])
			{
				low[cur] = min(low[cur], dfn[nxt]);
			}
		}
		if (dfn[cur] == low[cur])
		{
			cnt++; int top;
			do
			{
				top = lib.top(); lib.pop(); ins[top] = 0;
				belong[top] = cnt; scc[cnt].push_back(top);
			} while (top != cur);
		}
	}
	/*====================*/
	void Init(void)
	{
        num = cnt = 0;
		for (int i = 1; i <= n; ++i)
		{
			dfn[i] = low[i] = 0;
		}
		for (int i = 1; i <= n; ++i)
		{
			if (!dfn[i])Tarjan(i);
		}
	}
}

最小樹形圖

有向有環圖

挖坑:朱劉演算法

有向無環圖

namespace _DMST
{
	const int N = 1e5 + 10;
    /*====================*/
	const int INF = 0X7FFFFFFF;
	/*====================*/
	int val[N], sum;
	/*====================*/
	void Init(void)
	{
		sum = 0;
		for (int i = 1; i <= n; ++i)
		{
			val[i] = INF;
		}
		for (int i = 1; i <= m; ++i)
		{
			int u = edge[i].u;
			int v = edge[i].v;
			int w = edge[i].w;
			val[v] = min(val[v], w);
		}
		for (int i = 1; i <= n; ++i)
		{
			if (val[i] != INF)
			{
				sum += val[i];
			}
		}
	}
}

相關文章