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);
    }

}