hdu 6736 dfs

题目链接:hdu6736

这个题目由于题目对于给的图有很严重的限制,就是每个边最多只能处于一个简单的循环中,那么其实对于所有的图,都会是那种有一条链,链上的节点有个简单环,简单环的节点又有一条链如此反复。
通过分析其实就可以知道,对于每一个边数为n的环,让他变成树的方案数目是2^n -1;就是拆一条的方案+拆2条+。。。。+拆n条。
对于每一条单独的链,让他变成树的方案数是2^n ,因为链的话可以不用拆也是一种情况。那么答案就是乘上所有的环的方案数目在乘上所有链的方案数目。由于链的方案数最后是乘法所以你所有链的方案数就是所有链的边数的总和为n,链能给出的答案也是 2^n ; 也就是我们只要算出所有环的边数-去总边数得到的剩余边数就是所有链的边数,直接算答案就可以,不需要对于每一条链分别算答案。
接下来就是,如何求每一个环的边数,我采取的就是去记录下每个点的深度(像树那样),根的深度为1,因为这个图限制这么大才可以这么去求,当我发现一个节点(深度为d1)的一条边指向了我一个走过的点(深度为d2),那么我就发现了一个环,环的边数就是d2-d1+1;

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
#define  ll long long
using namespace std;
const int max_ = 1000000 + 50;
const ll p = 998244353;
inline int read() {
	int s = 0, f = 1;
	char ch = getchar();
	while (ch<'0' || ch>'9') {
		if (ch == '-')
			f = -1;
		ch = getchar();
	}
	while (ch >= '0'&&ch <= '9') {
		s = s * 10 + ch - '0';
		ch = getchar();
	}
	return s * f;
}
ll binaryPow(ll a, ll b, ll m) {
	ll ans = 1;
	while (b > 0) {
		if (b & 1) {
			ans =  ((ans%m)* (a % m))%m;
		}
		a =( (a%m) *(a % m))%m  ;
		b >>= 1;
	}
	return ans%m;
}
int head[max_], xiann = 2,n,m, deep[max_];
struct {
	int next, to,pan;
}xian[max_];
void add_(int a, int b) {
	xian[xiann].next = head[a];
	xian[xiann].to = b;
	xian[xiann].pan = 0;
	head[a] = xiann;
	xiann++;
}
int vis[max_], ans =1, num = 0;
stack<int> sta;
void dfs(int now, int fa, int dep) {
	vis[now] = 1;
	deep[now] = dep;
	for (int i = head[now]; i; i = xian[i].next) {
		if (xian[i].pan)continue;
		int to = xian[i].to;
		xian[i].pan = 1; xian[i ^ 1].pan = 1;
		if (vis[to]) {
			int t = deep[now] - deep[to] + 1;
			num += t;
			ans = ((ans%p)*((binaryPow(2, t, p) - 1) % p)) % p;
			ans %= p;
			continue;
		}
		dfs(to , now,dep+1);
	}
}

int main() {
	while (cin >> n >> m) {
		for (int i = 1; i <= m; i++) {
			int a = read(), b = read();
			add_(a, b); add_(b, a);
		}
		dfs(1, -1, 1);
		int t = m-num;
		ans = ((ans%p)*(binaryPow(2, t, p) % p)) % p;
		ans %= p;
		cout << ans<<endl;
		xiann = 2;
		for (int i = 0; i <= n + 1; i++) {
			deep[i] = head[i] = vis[i] = 0;
		}
		ans = 1; num = 0;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值