数据结构_基环树

题意

给一个n个点n条边的无向图(基环树特点嘤嘤嘤),找出有多少不同的简单路径。。。什么是简单路径,就是连接两个点的一条通路,但是如果只有方向不同,那么两条被视为一条简单路径。。

思路

分类讨论:
1.如果两个点都在环上,顺时针可以,逆时针也可以,ans = ans + 2;
2.如果一个点在环上,一个不在环上,而且不在同一棵树上,两条路径,经过环的时候顺时针走,逆时针走都可以,所以,ans = ans + 2;
3.如果在同一棵树上,那就只有一条,ans = ans + 1;
然后我们可以发现,只有在同一棵树上的时候才是ans + 1,那么我们就可以想到用 总的路径数(n * (n - 1)) - 所有的树的在同一棵树上的任意两个点之间的路径数(tot * (tot - 1)/ 2)的和

AC代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
vector<int>G[maxn];
int fa[maxn];
int vis[maxn];
int dfn[maxn];
int cnt = 0;
void find_loop(int now){//找环
	dfn[now] = ++cnt;
	for(int i = 0;i < G[now].size();i++){
		int to = G[now][i];
		if(to == fa[now]) continue;
		if(dfn[to]){
			if(dfn[to] < dfn[now]) continue;//???什么意思
			while(to != fa[now]){
				vis[to] = 1;
				to = fa[to];
			}
			return ;
		}
		fa[to] = now;
		find_loop(to);
	}
}
int dfs(int now){//寻找子树的结点的个数
	int num = 1;
	vis[now] = 1;
	for(int i = 0;i < G[now].size();i++){
		int to = G[now][i];
		if(vis[to]) continue;
		num += dfs(to);
	}
	return num;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n;
		scanf("%d",&n);
		for(int i = 1;i <= n;i++) G[i].clear();
		memset(fa,0,sizeof(fa));//存当前结点的父亲
		memset(vis,0,sizeof(vis));//有没有遇到过
		memset(dfn,0,sizeof(dfn));//访问的时间
		int u,v;
		for(int i = 1;i <= n;i++){
			scanf("%d%d",&u,&v);
			G[u].push_back(v);//vector存图
			G[v].push_back(u);
		}
		find_loop(1);//找环
		ll ans = 1ll * n * (n - 1);//全部的路径数
		for(int i = 1;i <= n;i++){
			if(vis[i]){
				ll tmp = dfs(i);//统计以i为根的子树的结点个数
				ans = ans - tmp * (tmp - 1) / 2;//减掉
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值