HDU - 6736 F - Forest Program
题意
给你n个点m条边,并且保证整个图是仙人掌。
仙人掌:每条边仅属于1条或者0条回路
且无重边和自环
让你删掉一些边使其变成一棵树(拥有点数-1条边)
注意一个点也是森林
图可能是不联通的
思路
考虑环,显然一个环可以随便去掉几条边但是至少一条(也就是说不能是\(C_n^0\))\(2^{x}\)-1,然后考虑非环那么共有m-(所有环的边数),然后可以随便去除边共\(2^{m-cnt}\)
在找环时,求环的边数见\(dfs\)
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
const int maxn=3e5+10;
int dep[maxn],cnt;
vector<int>edge[maxn];
const int mod=998244353;
int ans;
int qp(int a,int b) {
int res=1;
while(b) {
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
void dfs(int u,int fa) {
dep[u]=dep[fa]+1;
for(int i=0; i<edge[u].size(); ++i) {
int v=edge[u][i];
if(v==fa)continue;
if(!dep[v])dfs(v,u);
else if(dep[u]>dep[v]){
ans=(ans%mod*(qp(2,dep[u]-dep[v]+1)-1)%mod)%mod;
cnt+=dep[u]-dep[v]+1;
}
}
}
signed main() {
int n,m;
while(~scanf("%lld%lld",&n,&m)) {
cnt=0;
for(int i=1; i<=n; ++i)dep[i]=0,edge[i].clear();
for(int i=1; i<=m; ++i) {
int u,v;
scanf("%lld%lld",&u,&v);
edge[u].push_back(v);
edge[v].push_back(u);
}
ans=1;
for(int i=1; i<=n; ++i) {
if(!dep[i])dfs(i,0);
}
ans=(ans%mod*(qp(2,m-cnt))%mod)%mod;
printf("%lld\n",ans);
}
}