(本篇要点)dfs找环并计算图中环的长度。
Forest Program
题目传送门:
Forest Program
题目大意:
有n个点和m条无向边,要删去一些边使得剩下部分都为树(就是没有环)。问有多少删的方法。
思路:
如果n条边刚好构成一个环,那么这些边中就必须至少删去一条边,那么对于答案的贡献就是 res = res * ( 2 ^ n - 1 )。
如果n条边不够成环,那么怎么删都可以,那么对于答案的贡献就为 res = res * 2^n 。
所以关键就是dfs,找到每个环,并计算每个环的长度。所有边减去环中的边,剩下的边自然就是不在环中的边,可以随意删除。
AC Code
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=3e5+10,M=5e5+10;
const LL mod=998244353;
int head[N],cent=0;
struct Tree
{
int v,next;
}tr[M*2];
LL fac[M];
void add(int u,int v)
{
tr[cent].v=v;
tr[cent].next=head[u];
head[u]=cent++;
}
int dep[N],vis[N],n,m;
LL ans=1;
void dfs(int u,int fa)
{
vis[u]=1;
for(int i=head[u];~i;i=tr[i].next)
{
int to=tr[i].v;
if(to==fa) continue;
if(!vis[to])
{
dep[to]=dep[u]+1;
dfs(to,u);
continue;
}
if(dep[to]>dep[u]) continue;
int len=dep[u]-dep[to]+1;
ans=ans*(fac[len]-1)%mod;
m=m-len;
}
}
int main()
{
fac[0]=1;
for(int i=1;i<=M;i++)
fac[i]=fac[i-1]*2%mod;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<=n;i++)
{
head[i]=-1;
dep[i]=0;
vis[i]=0;
}
cent=0,ans=1;
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dep[i]=1;
dfs(i,0);
}
}
ans=ans*fac[m]%mod;
printf("%lld\n",ans);
}
//system("pause");
return 0;
}