HDU - 6736(找环)

该博客讨论了一个图论问题,即如何从仙人掌图(一种特殊的无环图)中删除边,使得剩余的连通分量全部变为树。通过计算不同环和非环部分的边删除方案,可以得出总的方案数。程序通过DFS遍历图并计算环的长度来实现这一策略,并输出结果模998244353。这个问题有助于理解和应用图的结构转换在阻止沙漠化问题上的模拟。
摘要由CSDN通过智能技术生成

HDU - 6736(找环)

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个顶点和m个边的无向图,并且所有连通的分量都是cactus,你应该确定在图中去除边的方案的个数,这样剩下的连通分量都是树。打印答案模块998244353。
当且仅当两个方案中的去除边集不同时,两个方案被认为是不同的。
输入
第一行包含两个非负整数n,m(1≤n≤30万,0≤m≤50万),表示给定图中的顶点数和边数。
接下来的m行每行包含两个正整数u,v(1≤u,v≤n,u=v),表示顶点u和v由无向边连接。
保证输入图中的每个连通分量都是仙人掌。
输出
输出包含非负整数的单行,表示应答模998244353。

思路

对于一个长度为k的环 我们可以有2^k -1种删边的方式(减去全都不删的那一种)
对于长度为k的非环部分 我们有2^k种方式
答案就是他们的乘积

Code

#include<string>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define LL long long
#define MOD 998244353
#define PI 3.1415926535898
#define INF 0x3f3f3f3f
#define MAXN 80000080
const double EPS = 1e-8;
LL read()
{
	LL x = 0, w = 1;
	char ch = 0;
	while (ch < '0' || ch>'9')
	{
		if (ch == '-')
		{
			w = -1;
		}
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return w * x;
}
LL cnt, n, m, head[300050], pr[300050], ti[300050], xx, yy, sh, sum, cn;
bool v[300050];
struct node
{
	int to, next;
}edge[1000000];
void add(int x, int y)
{
	edge[++cnt].next = head[x];
	edge[cnt].to = y;
	head[x] = cnt;
}
LL p[500050];
void dfs(int x, int pre)
{
	ti[x] = ++cn;
	pr[x] = pre;
	v[x] = 1;
	for (register int i = head[x]; i; i = edge[i].next)
	{
		if (edge[i].to == pre)
			continue;

		if (!v[edge[i].to])
		{
			dfs(edge[i].to, x);
		}
		else if (ti[x] > ti[edge[i].to])
		{
			int now = x;
			int s = 1;
			while (now != edge[i].to)
			{
				s++;
				now = pr[now];
			}
			sh -= s;
			sum *= (p[s] - 1);
			sum %= MOD;
		}
	}
}
int main()
{
	p[0] = 1;
	for (register int i = 1; i <= 500000; i++)
	{
		p[i] = p[i - 1] * 2;
		p[i] %= MOD;
	}
	while (cin >> n)
	{
		sum = 1;
		m = read();
		cn = 0;
		sh = m;
		memset(ti, 0, sizeof(ti));
		memset(head, 0, sizeof(head));
		memset(edge, 0, sizeof(edge));
		memset(v, 0, sizeof(v));
		memset(pr, 0, sizeof(pr));
		for (register int i = 1; i <= m; i++)
		{
			xx = read();
			yy = read();
			add(xx, yy);
			add(yy, xx);
		}
		dfs(1, 0);
		sum *= p[sh];
		sum %= MOD;
		cout << sum << endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值