HDU - 6736 F - Forest Program

WarYan發表於2020-10-19

題意

給你n個點m條邊,並且保證整個圖是仙人掌。

仙人掌:每條邊僅屬於1條或者0條迴路

且無重邊和自環

讓你刪掉一些邊使其變成一棵樹(擁有點數-1條邊)

注意一個點也是森林

圖可能是不聯通的

思路

考慮環,顯然一個環可以隨便去掉幾條邊但是至少一條(也就是說不能是 C n 0 C_n^0 Cn0) 2 x 2^{x} 2x-1,然後考慮非環那麼共有m-(所有環的邊數),然後可以隨便去除邊共 2 m − c n t 2^{m-cnt} 2mcnt

在找環時,求環的邊數見 d f s dfs 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);
    }

}

相關文章