洛谷P2860 [USACO06JAN]Redundant Paths G (tarjan,边双缩点)
本题的大意就是加最少的边使得图成为边双。
多举例子,画图分析可得:最终答案就是叶子节点(度数为1的点)的个数加1在除以2。
那么我们的目的就转化为找叶子节点:
首先通过tarjan找到割边,再dfs将原图分为几个边双(通过割边划分),缩点,最后统计度数为1的节点个数即可。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 100100; 4 int n, m, ans, tot = 1, cnt, sum; 5 int dfn[N], low[N]; 6 int head[N], to[N], nxt[N]; 7 int num[N], du[N], way[N]; 8 void add(int u, int v) { 9 nxt[++ tot] = head[u]; head[u] = tot; to[tot] = v; 10 } 11 void tarjan(int u, int fa) {//fa是u的父亲边,该函数目的是为了找割边,不需要栈 12 low[u] = dfn[u] = ++ cnt; 13 for (int i = head[u]; i; i = nxt[i]) { 14 int v = to[i]; 15 if (!dfn[v]) { 16 tarjan(v, i); 17 low[u] = min(low[u], low[v]); 18 if (low[v] > dfn[u]) way[i] = way[i ^ 1] = 1;//找到割边 19 } 20 else if ((i ^ 1) != fa) low[u] = min(low[u], dfn[v]); 21 } 22 } 23 void dfs(int u) { 24 num[u] = sum; 25 for (int i = head[u]; i; i = nxt[i]) { 26 int v = to[i]; 27 if (way[i] || num[v]) continue; 28 dfs(v); 29 } 30 } 31 int main() { 32 scanf("%d %d", &n, &m); 33 while (m --) { 34 int x, y; 35 scanf("%d %d", &x, &y); 36 add(x, y), add(y, x); 37 } 38 tarjan(1, 0); 39 for (int i = 1; i <= n; i ++) 40 if (!num[i]) {sum ++; dfs(i);} 41 for (int i = 1; i <= n; i ++) { 42 for (int j = head[i]; j; j = nxt[j]) { 43 int v = to[j]; 44 if (num[i] != num[v]) du[num[v]] ++; 45 } 46 } 47 for (int i = 1; i <= sum; i ++) 48 if (du[i] == 1) ans ++; 49 ans = (ans + 1) / 2; 50 printf("%d\n", ans); 51 return 0; 52 }
如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
标签:
tarjan
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现