题目描述
给定一张有 n 个顶点 m 条边的无向连通图 G,顶点依次以 1,2,…,n 编号。G 有以下特殊的性质:
- G 中的每条边至多属于一个简单环。
- G 中没有重边与自环。
简单环是指环中顶点互不相同,且不经过重复边的回路。
请你求出 G 的不同生成树的数量。两棵生成树不同,当且仅当存在一条边在其中一棵生成树中出现,而不在另一棵生成树中出现。
由于答案可能很大,你只要求出答案对 998244353 取模的结果。
输入格式
第一行,两个正整数 n,m,分别表示 G 的顶点数与边数。
接下来 m 行,每行两个整数 ui,vi,表示一条连接顶点 ui,vi 的无向边。
输出格式
输出一行,一个整数,表示 G 的不同生成树的数量对 998244353 取模的结果。
输入输出样例
输入 #1复制
7 8 1 2 2 3 3 1 3 4 4 5 5 6 6 7 7 4
输出 #1复制
12
输入 #2复制
5 4 1 2 1 3 2 4 2 5
输出 #2复制
1
说明/提示
对于 40% 的测试点,保证 1≤n≤8,1≤m≤10。
对于 60% 的测试点,保证 1≤n≤2000,1≤m≤2000。
对于所有测试点,保证 1≤n≤105,1≤m≤105,1≤ui,vi≤n。
代码实现:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MOD = 998244353;
const int MAXN = 100005;
vector<int> g[MAXN];
int dfn[MAXN], low[MAXN], tim;
int stk[MAXN], top;
ll ans = 1;
void tarjan(int u, int fa)
{
dfn[u] = low[u] = ++tim;
stk[++top] = u;
for (int v : g[u])
{
if (v == fa) continue;
if (!dfn[v])
{
tarjan(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > dfn[u])
{
top--;
}
else if (low[v] == dfn[u])
{
int cnt = 0;
while (true)
{
cnt++;
if (stk[top] == v) break;
top--;
}
top--;
ans = ans * (cnt + 1) % MOD;
}
}
else
{
low[u] = min(low[u], dfn[v]);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
tarjan(1, -1);
cout << ans << endl;
return 0;
}
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/Jasmine_llq/article/details/167085126


![《P17461 [GESP202609 八级] 生成树计数》封面图](https://i-blog.csdnimg.cn/direct/8971eae46b9440569e312c23e34090b9.png?x-oss-process=image/resize,m_fixed,h_300)

