2019CCPC秦皇岛赛区 hdu 6736 Forest Program(dfs找出所有环的大小&&组合计数)

传送门

Forest Program

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1745    Accepted Submission(s): 612


Problem Description
The kingdom of Z is fighting against desertification these years since there are plenty of deserts in its wide and huge territory. The deserts are too arid to have rainfall or human habitation, and the only creatures that can live inside the deserts are the cactuses. In this problem, a cactus in desert can be represented by a cactus in graph theory.
In graph theory, a cactus is a connected undirected graph with no self-loops and no multi-edges, and each edge can only be in at most one simple cycle. While a tree in graph theory is a connected undirected acyclic graph. So here comes the idea: just remove some edges in these cactuses so that the remaining connected components all become trees. After that, the deserts will become forests, which can halt desertification fundamentally.
Now given an undirected graph with n vertices and m edges satisfying that all connected components are cactuses, you should determine the number of schemes to remove edges in the graph so that the remaining connected components are all trees. Print the answer modulo 998244353.
Two schemes are considered to be different if and only if the sets of removed edges in two schemes are different.
 

Input
The first line contains two non-negative integers n, m (1 ≤ n ≤ 300 000, 0 ≤ m ≤ 500 000), denoting the number of vertices and the number of edges in the given graph.
Next m lines each contains two positive integers u, v (1 ≤ u, v ≤ n, u = v), denoting that vertices u and v are connected by an undirected edge.
It is guaranteed that each connected component in input graph is a cactus.
 

Output
Output a single line containing a non-negative integer, denoting the answer modulo 998244353.
 

Sample Input
    
    
    
    
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

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

题意:

就是给一个图,让去一些边把他变成森林(就是变成很多树),如果存在环的话,那肯定是要删至少一条边,但如果不是环上的边就有两种可能可删可不删

考虑一个环有n个点(环的点和边相等),那么要想变成树至少删掉一条边,那可能的情况就有2^n-1种(每条边都有可删可不删两种情况,总的是 2^n,然后全部不删是不满足的,所以减1)

那么只要找到所以环的大小即可
dfs找环,如果发现他的儿子节点遍历过(并且这个儿子的深度比他小),那么说明出现了环,这个儿子其实是他的祖先,然后算一下环的大小即可(可以发现深度之差+1就是环的大小,画一下或者debug就想明白了),然后顺便统计环上的边记为sum,m-sum就是非环上的边,最后乘以2^(m-sum)
根据乘法原则,把所以的情况乘起来即是结果ans

代码:

ll quick(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        b/=2;
    }
    return ans;
}
vector<int>p[MAXN];
bool vis[MAXN];
int dep[MAXN];//深度
ll ans=1;
int sum=0;
void dfs(int x,int fa){
    vis[x]=1;
    dep[x]=dep[fa]+1;

    for(auto y:p[x]){

        if(y==fa)continue;

        if(!vis[y])dfs(y,x);
        else if(dep[x]>dep[y]){
            
            ans=ans*(quick(2,dep[x]-dep[y]+1)-1+mod)%mod;
            
            sum+=dep[x]-dep[y]+1;//统计所有环上边的个数
        }
    }
}
int main()
{
    std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n,m;
	cin>>n>>m;
    memset(vis,0,sizeof(vis));
    ans=1;
    sum=0;
    for(int i=1;i<=m;i++){
        int u,v;
        cin>>u>>v;
        p[u].pb(v);
        p[v].pb(u);
    }
    for(int i=1;i<=n;i++)if(!vis[i])
    dfs(i,0);
    

    ans=(ans*(quick(2,m-sum)))%mod;//m-sum非环上的边
    cout<<ans<<endl;

    return 0;
}

你可能感兴趣的:(树,dfs)