Forest Program 2019CCPC秦皇岛F

Forest Program 2019CCPC秦皇岛F (hdu重现赛)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6736
在这里插入图片描述

题意

一个 n 个节点 m 条边的无向图,没有重边和自环,每条边被至多一个简单环覆盖,要求去掉一些边使剩余的连通部分都为树(即使图成为森林),问有多少种方案。

思路

每条边都有去掉和不去掉两个状态,但剩余部分不能有环
设成环的边数分别为 c1 , c2 , c3 …ck
不成环的边数为 b
答案 ans = 2 b 2^{b} 2b * ∏ i = 1 k \prod_ {i=1} ^ {k} i=1k ( 2 c i − 1 2^{ci}-1 2ci1)

用 dfs 暴力一下每个环的边数,book[] 存的是到达每个节点的步数,book[1]=1, 从1开始dfs;
设当前为节点i , 和 i 连接的下一个节点为 j ,若 book [ j ] >0&&book [ j ] < book [ i ], 即有一个环。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+10;
const int mod=998244353;

int n,m;
int head[N];
vector<int> v[N];
vector<int> cnt;
int book[N];
void dfs(int p,int num)
{
    book[p]=num;
    for(int i=0; i<v[p].size(); i++)
    {
        if(book[v[p][i]]<num&&book[v[p][i]]>0&&num-book[v[p][i]]>1)
        {
            cnt.push_back(num-book[v[p][i]] +1) ;
        }
        else if(book[v[p][i]]==0)
        {
            dfs(v[p][i],num+1);
        }
    }
}
ll quick_pow(ll x,ll n)
{
    ll res=1;
    while(n>0)
    {
        if(n&1)
            res=(res%mod*x%mod)%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}
int main()
{
    std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    while(cin>>n>>m)
    {
        int l,r;
        for(int i=1; i<=n; i++)
            v[i].clear();
        for(int i=1; i<=m; i++)
        {
            cin>>l>>r;
            v[l].push_back(r);
            v[r].push_back(l);
        }
        memset(book,0,sizeof(book));
        cnt.clear();
        dfs(1,1);
        ll sum=0,ans=1;
        for(int i=0; i<cnt.size(); i++)
        {
            sum+=cnt[i];
            ans=(ans*(quick_pow(2,cnt[i])-1))%mod;
        }
        ans=(ans*quick_pow(2,(ll)m-sum)%mod)%mod;
        cout<<ans<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值