2019 CCPC 秦皇岛 :Forest Program

(本篇要点)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;
}

猜你喜欢

转载自blog.csdn.net/Stevenwuxu/article/details/110009302
今日推荐