洛谷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 }
复制代码

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   YHXo  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示