题目描述
给定一张有 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。
代码实现:
cpp
#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;
}