求助大佬 #2 #11WA

P2860 [USACO06JAN] Redundant Paths G

可是我一遍就过了啊 ![](https://cdn.luogu.com.cn/upload/image_hosting/qktdtpoa.png)
by 华年 @ 2022-07-21 17:44:13


先贴一个我的代码 基本思路也是先缩点, 再建新图, 再统计叶子数(我用的 dfs). 等下我看看你的代码 ```cpp #include <stack> #include <stdio.h> #include <memory.h> #include <algorithm> #define eto e[i].to #define etoo e2[i].to #define en e[i].n #define enn e2[i].n const int maxn = 1e4 + 5, maxm = 1e5 + 6; typedef int imaxn[maxn]; // scc, strong connected component, 强连通分量 // dfn 是时间戳 // low 是能够追溯到的最早的栈中节点的时间戳. imaxn head, head2, dfn, low, scc, degree, dp, flag; int cnt, cnt2, idx, n, m, dfsClock; std::stack<int> s; struct edge { int to, n; } e[maxm * 2], e2[maxm * 2]; // 有向图 void add(int u, int v) { e[++cnt].to = v; e[cnt].n = head[u]; head[u] = cnt; } void add2(int u, int v) { e2[++cnt2].to = v; e2[cnt2].n = head2[u]; head2[u] = cnt2; } void tarjan(int, int); void dfs(int); int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); #endif scanf("%d %d", &n, &m); for (int i = 1, u, v;i <= m;i++) { scanf("%d %d", &u, &v); add(u, v); add(v, u); } for (int i = 1;i <= n;i++) if (!dfn[i]) tarjan(i, 0); // 建立新图 for (int u = 1;u <= n;u++) for (int i = head[u];i;i = en) if (scc[u] != scc[eto]) { add2(scc[u], scc[eto]); add2(scc[eto], scc[u]); // printf("%d -> %d\n", scc[u], scc[eto]); } dfs(1); int ans = 0; for (int i = 1;i <= idx;i++) if (degree[i] == 1) ans++; printf("%d", (ans + 1) / 2); return 0; } void tarjan(int u, int fa) { dfn[u] = low[u] = ++dfsClock; // 更新时间戳 s.push(u); for (int i = head[u];i;i = en) { if (eto == fa) continue; if (!dfn[eto]) { tarjan(eto, u); low[u] = std::min(low[u], low[eto]); // 自己和自己的儿子在同一个 scc 中 } else if (!scc[eto]) // 如果他的儿子已经被更新过了, 并且这个儿子不在已知的强连通分量中, 那么这个儿子和自己在同一个 scc 中, 并且这个儿子有可能就是所在 scc 中 dfn 最小的一个 low[u] = std::min(low[u], dfn[eto]); } if (dfn[u] == low[u]) // 自己是自己所在的 scc 中 dfn 最小的一个 { idx++; int x; // printf("[%d] : ", idx); while (true) { x = s.top(); s.pop(); // printf("%d ", x); scc[x] = idx; if (x == u) break; } // puts(""); } } void dfs(int u) { flag[u] = true; for (int i = head2[u];i;i = enn) if (!flag[etoo]) { degree[u]++; degree[etoo]++; dfs(etoo); } return; } ```
by 华年 @ 2022-07-21 17:47:25


与代码本身有关的细节放在[这里](https://www.luogu.com.cn/paste/xe3oglbz)了 接下来说一下我看出来的你原来的做法所存在的问题 我其实不知道你想怎么用你标记的桥的, 写了一大段最后还是删了. 不过不用讨论了, 你明白就行, 可以尝试一下把你的版本改对. 这里也许有问题. ```cpp for(int i = first[x]; i&&((!mark[i])&&(!mark[i^1])); i = edge[i].next) { int y = edge[i].to; if(!vis[y]) dfs(y); } ``` 也许应该是这样才正确 ```cpp for(int i = first[x];i;i = edge[i].next) if (!mark[i] && !mark[i^1]) { int y = edge[i].to; if(!vis[y]) dfs(y); } ``` 不解释了, 你应该能明白. 改了这个地方之后 #2 就 A 了好像. 还有这个地方 ```cpp for(int i = 2; i <= cnt; i++) //加入桥 { if(!mark[i]) continue; int x = edge[i].from; int y = edge[i].to; leaf[co[x]]++; leaf[co[y]]++; } ``` 由于是无向图, 所以我第一眼就觉得这里有问题. 不过因为你跳过了标记的桥, 这些桥不在 scc 中, 所以无向图变成了有向图, 就没问题了. 后来 #9 #10 WA 了, 我下载数据一看, 发现有重边. 果然删掉重边之后就对了, 所以还是有问题. 解决方法我想到了两个, 一是 `dfs()` + `vis[]`, 二是拓扑排序. 我选择了第一种. 所以说你原来能得那么高的分, 说明数据有点水.
by 华年 @ 2022-07-21 21:08:56


@[华年](/user/240858) 感谢大佬细节说明,真是太巨了!!!
by Future_zxs @ 2022-07-21 22:41:04


|