2019ccpc秦皇岛F(DFS判环)

23 篇文章 0 订阅

Problem Description

Z 国近年来一直在考虑遏制国土沙漠化的方案。在 Z 国广阔的疆域上,有着许多的沙漠。沙漠上干旱少雨,荒无人烟,仅有仙人掌能在这种魔鬼环境中生存。经过 Z 国地质探测局的调查,他们得到了沙漠的实地情况。Z 国的地质探测局是一个热爱 CCPC 的机构,他们喜欢使用图论的方式来描述看到的景色。在得到的数据中,沙漠中的每一个连通块都是一棵仙人掌;一个连通块是一棵仙人掌当且仅当连通块中不存在重边和自环,并且每一条边仅被至多一个简单环覆盖。

经过一番评估,Z 国决定通过删去沙漠中的一些边,最终将沙漠变为森林。这里我们定义森林满足:森林中每一个连通块都是一棵树,而树是边数等于点数减一的连通块。现在给定一个包含 n 个点的沙漠,请你求出 Z 国一共有多少种满足要求的沙漠改造方案。两种方案不同当且仅当方案中被删去的边集不同。由于答案可能很大,请将最终答案对 998244353 取模后输出。

Input

多组数据,每组数据第一行输入两个非负整数 n、m,分别表示沙漠中的点数和边数。沙漠中点的编号为 1, 2, ..., n。

对于每组数据的第 2 到第 m+1 行,每行输入两个正整数 u、v,表示沙漠中编号为 u 和编号为 v 的两个点之间有边相连。

1≤T≤3,1≤n≤3×105,m≤5×105,1≤u, v≤n 并且 u≠v。



样例解释



对于第一组样例,只需要至少删去一条边即可变为森林,故一共有 23−1=7 种方案。

 

Output

对于每一组数据,输出一行一个非负整数,表示答案对 998244353 取模后的值。

 

Sample Input

2

3 3

1 2

2 3

3 1

6 6

1 2

2 3

3 1

2 4

4 5

5 2

Sample Output

7

49

找到有几个环然后判断环的大小,最少删掉一条边,所以方案就是2^环的边数,因为还有那些没成环的所以方案数需要在乘上2^没成环的边数。

用dfs找环

AC代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<map>
#include<iomanip>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double ld;
const int maxn = 5e5 + 10;
const int maxm = 5e5 + 10;
const int mod = 998244353;
vector<int>e[maxn];
int vis[maxn],dfn[maxm],no[maxn],cnt;
ll ans;

void dfs(int now,int u,int f)
{
    vis[u]=1;
    no[u]=now;
    for(int i=e[u].size()-1; i>=0; i--)
    {
        int v=e[u][i];
        if(v==f)
            continue;
        if(!vis[v])
            dfs(now+1,v,u);
        else if(now>no[v])
        {
            ans=ans*(ll)(dfn[now-no[v]+1]-1)%mod;
            cnt=cnt-(now-no[v]+1);
        }
    }
}

int main()
{
    int n,m;
    dfn[0]=1;
    for(int i=1; i<maxm; ++i)
        dfn[i]=dfn[i-1]*2%mod;
    scanf("%d %d",&n,&m);
    ans=1;
    if(m==0)
        printf("1\n");
    else
    {
        cnt=m;
        for(int i=0; i<m; ++i)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            e[u].push_back(v);
            e[v].push_back(u);
        }
        for(int i=1; i<=n; ++i)
            if(!vis[i])
              dfs(0,i,0);
        ans=ans*ll(dfn[cnt])%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值