首页 > 其他分享 >图论基础模板

图论基础模板

时间:2023-03-23 21:33:05浏览次数:48  
标签:head last int 基础 图论 low cnt 模板 define

P3388 【模板】割点(割顶)

#include <stdio.h>
#define min(x, y) ((x) < (y) ? (x) : (y))

int n, m;
int head[20003], last[200003], to[200003], ccnt = 0;
#define addedge(x, y) last[++ccnt] = head[x], to[ccnt] = y, head[x] = ccnt
int dfn[20003], low[20003], cnt = 0;
bool f[20003]; int ans = 0;

inline void dfs (int x, int fa) {
	dfn[x] = low[x] = ++cnt;
	int child = 0;
	#define y to[k]
	for (int k = head[x]; k; k = last[k]) if (!dfn[y]) {
		dfs(y, x), ++child;
		low[x] = min(low[x], low[y]);
		if (!fa && child > 1 || fa && low[y] >= dfn[x]) f[x] = 1;
	}
	else	low[x] = min(low[x], dfn[y]);
	#undef y
}

inline void kagari () {
	scanf("%d %d", &n, &m); for (int i = 1; i <= m; ++i) { int x, y; scanf("%d %d", &x, &y); addedge(x, y), addedge(y, x); }
	for (int i = 1; i <= n; ++i) low[i] = i;
	for (int i = 1; i <= n; ++i) if (!dfn[i]) dfs(i, 0);
	for (int i = 1; i <= n; ++i) if (f[i]) ++ans;
	printf("%d\n", ans); 
	for (int i = 1; i <= n; ++i) if (f[i]) printf("%d ", i);
	return;
}

int main () {
	kagari();
	return 0;
}

P8435 【模板】点双连通分量

在求割点的基础上运行. 就是对于一个连通图, 我们按照dfs的顺序将访问的节点放到一个 stack 中, 然后如果发现某个点是割点 ( 显然这是对某个儿子节点 dfs 之后发现的), 便将stack 一直弹出直到 top 是这个割点, 弹出的内容物便是一个点双连通分量.

一些定义可以看一下 https://www.luogu.com.cn/blog/zaczac/solution-p8435

#include <stdio.h>
#include <vector>
#include <stack>
#define min(x, y) ((x) < (y) ? (x) : (y))

int n, m;
int head[500003], last[4000003], to[4000003], ccnt = 0;
#define addedge(x, y) last[++ccnt] = head[x], to[ccnt] = y, head[x] = ccnt
int dfn[500003], low[500003], cnt = 0;
std:: stack < int > s;
std:: vector < int > v[1000003]; int ans = 0;

inline void dfs (int x) {
	dfn[x] = low[x] = ++cnt, s.push(x);
	#define y to[k]
	for (int k = head[x]; k; k = last[k]) if (!dfn[y]) {
		dfs(y);
		low[x] = min(low[x], low[y]); 
		if (low[y] >= dfn[x]) {
			++ans;
			while (!s.empty()) { int t = s.top(); v[ans].push_back(t), s.pop(); if (t == y) break; }
			v[ans].push_back(x);
		}
	} else low[x] = min(low[x], dfn[y]);
	#undef y
}

inline void kagari () {
	scanf("%d %d", &n, &m); for (int i = 1; i <= m; ++i) { int x, y; scanf("%d %d", &x, &y); if (x == y) continue; addedge(x, y), addedge(y, x); }
	for (int i = 1; i <= n; ++i) if (!dfn[i]) {
		if (head[i]) dfs(i);
		else v[++ans].push_back(i);
	}
	printf("%d\n", ans);
	for (int i = 1; i <= ans; ++i, puts("")) { printf("%d ", v[i].size()); for (int j: v[i]) printf("%d ", j); }
	return;
}

int main () {
	kagari();
	return 0;
}

P4782 【模板】2-SAT 问题

#include <stdio.h>
#include <stack>
#define min(x, y) ((x) < (y) ? (x) : (y))
int n, m;
int head[2000003], last[2000003], to[2000003], ccnt = 0;
#define addedge(x, y) last[++ccnt] = head[x], to[ccnt] = y, head[x] = ccnt
int dfn[2000003], low[2000003], dnt = 0; bool vis[2000003];
int color[2000003], cnt = 0;
std:: stack < int > s;

inline void dfs (int x) {
	dfn[x] = low[x] = ++dnt, vis[x] = true, s.push(x);
	for (int k = head[x]; k; k = last[k]) 
		if (!dfn[to[k]]) dfs(to[k]), low[x] = min(low[x], low[to[k]]); 
		else if (vis[to[k]]) low[x] = min(low[x], dfn[to[k]]);
	if (dfn[x] == low[x]) {
		++cnt;
		while (!s.empty() && s.top() != x) color[s.top()] = cnt, vis[s.top()] = false, s.pop();
		color[s.top()] = cnt, vis[s.top()] = false, s.pop();
	}
}

inline void kagari () {
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= m; ++i) { int x, y, z, l; scanf("%d %d %d %d", &x, &y, &z, &l); if (x == z && y != l) continue;
		addedge(z + (l ^ 1) * n, x + y * n), addedge(x + (y ^ 1) * n, z + l * n); }
	for (int i = 1; i <= (n << 1); ++i) if (!dfn[i]) dfs(i);
	for (int i = 1; i <= n; ++i) if (color[i] == color[i + n]) { printf("IMPOSSIBLE\n"); return; }
	puts("POSSIBLE");
	for (int i = 1; i <= n; ++i) if (color[i] > color[i + n]) printf("1 "); else printf("0 ");
	return;
}

int main () {
	kagari();
	return 0;
}

P3376 【模板】网络最大流

EK 算法, 时间复杂度 \(O(nm^2)\). 每次寻找一条 S -> T 的路, 并记录这条路径的最小值.

#include <stdio.h>
#include <queue>
#define ll long long
#define min(x, y) ((x) < (y) ? (x) : (y))

int n, m, st, en;
int head[203], to[10003], last[10003], cnt = 1; ll val[10003];
#define addedge(x, y, z) to[++cnt] = y, val[cnt] = z, last[cnt] = head[x], head[x] = cnt
bool vis[203]; ll dis[203]; int frm[203];

inline bool bfs () {
	for (int i = 1; i <= n; ++i) vis[i] = false;
	std:: queue < int > q; q.push(st), dis[st] = 2147483648ll, vis[st] = true;
	while (!q.empty()) {
		int x = q.front(); q.pop();
		#define y to[k]
		for (int k = head[x]; k; k = last[k]) if (val[k] != 0 && !vis[y]) {
			vis[y] = true, dis[y] = min(dis[x], val[k]), frm[y] = k, q.push(y);
			if (y == en) return true;
		}
		#undef y
	}
	return false;
}

ll ans = 0;
inline void update () {
	ans += dis[en];
	int t = en; while (t != st) val[frm[t]] -= dis[en], val[frm[t] ^ 1] += dis[en], t = to[frm[t] ^ 1];
}

inline void kagari () {
	scanf("%d %d %d %d", &n, &m, &st, &en);
	for (int i = 1; i <= m; ++i) { int x, y; ll z; scanf("%d %d %lld", &x, &y, &z); addedge(x, y, z), addedge(y, x, 0); }
	while (bfs()) update();
	printf("%lld\n", ans);
	return;
}

int main () {
	kagari();
	return 0;
}

dinic 算法, 先进行 bfs, 计算每个点与源点的距离 \(dep_i\). 我们令节点 \(x\) 只能前往节点 \(y\), 当且仅当 \(dep_y=dep_x+1\). 时间复杂度 \(O(n^2m)\)

#include <stdio.h>
#include <queue>
#define ll long long
inline int min(int x, int y) { return ((x) < (y) ? (x) : (y)); }
inline ll min(ll x, ll y) { return ((x) < (y) ? (x) : (y)); }

int n, m, st, en;
int head[203], to[10003], last[10003], cnt = 1; ll val[10003];
#define addedge(x, y, z) to[++cnt] = y, val[cnt] = z, last[cnt] = head[x], head[x] = cnt
int dep[203], frm[203], nh[203];
ll ans = 0;

inline bool bfs () {
	for (int i = 1; i <= n; ++i) dep[i] = 1000;
	std:: queue < int > q; q.push(st), dep[st] = 1, nh[st] = head[st];
	while (!q.empty()) {
		int x = q.front(); q.pop();
		#define y to[k]
		for (int k = head[x]; k; k = last[k]) if (val[k] > 0 && dep[y] == 1000) {
			dep[y] = dep[x] + 1, nh[y] = head[y], q.push(y);
			if (y == en) return true;
		}
		#undef y
	}
	return false;
}

inline ll dfs (int x, ll sum) {
	if (x == en) return sum;
	ll cum = 0ll;
	#define y to[k]
	for (int k = nh[x]; k && sum; k = last[k]) {
		nh[x] = k; 
		if (val[k] > 0 && dep[y] == dep[x] + 1) {
			ll cost = dfs(y, min(sum, val[k]));
			if (cost == 0) dep[y] = 1000;	// 剪枝 ( 从 y 流不到汇点 )
			val[k] -= cost, val[k ^ 1] += cost, sum -= cost, cum += cost;
		}
	}
	#undef y
	return cum;
}

inline void kagari () {
	scanf("%d %d %d %d", &n, &m, &st, &en);
	for (int i = 1; i <= m; ++i) { int x, y; ll z; scanf("%d %d %lld", &x, &y, &z); addedge(x, y, z), addedge(y, x, 0); }
	ll ans = 0ll;
	while (bfs()) ans += dfs(st, 2147483648ll);
	printf("%lld\n", ans);
	return;
}

int main () {
	kagari();
	return 0;
}

标签:head,last,int,基础,图论,low,cnt,模板,define
From: https://www.cnblogs.com/dbg-8/p/17239473.html

相关文章

  • 昇腾AI深耕沽上:港口辐射力之后,天津再添基础创新辐射力
    作者|曾响铃文| 响铃说AI计算正在以新基建联动产业集群的方式,加速落地。不久前,天津市人工智能计算中心正式揭牌,该中心整体规划300P算力,2022年底首批100P算力上线投入运......
  • Java面试-基础篇之5
    说一说synchronized关键字synchronized是java语言中的一个关键字,如同public、private、trycatch等可以在Java中直接被编译器识别的具有功能性的单词。synchronized中文意......
  • Python基础
    列表方法用法案例字符串方法字典方法用法案例集合方法1方法2用法案例文件对象方法......
  • work中模板、主题、样式集、样式的作用和使用方法
    【收藏】Word样式、样式集、主题、模版怎么区分?进来围观学习了~ 我们先来按照层次关系从小到大排序:样式<样式集<主题<模板接下来,我们按照层次关系从小到大开始了解它......
  • MySQL基础:事务
    MySQL基础:事务事务简介事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时......
  • linux shell基础--$字符
    shell中有两类字符:普通字符、元字符。普通字符在Shell中除了本身的字面意思外没有其他特殊意义,即普通纯文本;元字符是Shell的保留字符,在Shell中有着特殊的含义。$()反引号......
  • 智能开放、超高性能、超低时延, 星融元数据中心网络解决方案重新定义网络基础设施
    随着数据流量的不断增长,特别是大数据时代到来后,各行业业务产生的流量激增,数据中心面临着来自应用和数据的网络压力也在“狂飙”。数据中心亟待解决数据中心之间的海量数据高......
  • 【STM32】库函数开发项目模板
    1.下载固件库官方网址:https://www.st.com工具与软件->嵌入式软件->安全微控制器软件->微控制器软件->STM32微控制器软件->STM32标准外设软件库直达链接:https......
  • 【0基础学爬虫】爬虫基础之代理的基本使用
    大数据时代,各行各业对数据采集的需求日益增多,网络爬虫的运用也更为广泛,越来越多的人开始学习网络爬虫这项技术,K哥爬虫此前已经推出不少爬虫进阶、逆向相关文章,为实现从易......
  • Quicker快速开发,简单的网页数据爬取(示例,获取天眼查指定公司基础工商数据)
    前言有某个线上项目,没有接入工商接口,每次录入公司的时候,都要去天眼查、企查查或者其他公开数据平台,然后手动录入,一两个还好说,数量多了的重复操作就很烦,而且,部分数据是包含......