CodeForces - 1454E

题目链接

题意:T组测试:每组测试给一图, n和节点n条边且是连通图;问有多少种长度大于等于1的简单路径。
解题思路:
根据已知信息可知:
1.图是一个n个节点n条边的连通图, 那么图中必然有一个环~~(loop)~~ ;
2.长度大于等于1的简单路径为任意两点间的路径;

根据这两个信息可推出:
①.在环中的任意两点皆有两条路径;
②.以环为根节点的左子树上的点与右子树上的点之间也是有两条路径;
③.以环为根节点左子树中任意两点只有一条路径,右子树一样;

那么,若n个节点n条边的连通图任意两点的路径条数都为2 则有 sum = n * (n - 1) 条,用 sum - ③中得到的路径数,
即为所求。

代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
typedef long long LL;
const int maxn = 2e5 + 7, maxm = 4e5 + 7;

int h[maxn], e[maxm], ne[maxm], cnt;
int d[maxn], vis[maxn], jud[maxn];
LL s[maxn];

void add(int u, int v){
	e[cnt] = v;
	ne[cnt] = h[u];
	h[u] = cnt ++;
}
vector<int> loop; // 存储环中的节点
int n;
void topsort(){   // 桶过拓扑排序的方法 可以得到环中的结点
	memset(vis, 0, sizeof vis);
	queue<int> q;
	for (int i = 1; i <= n; i ++ ) if (d[i] == 1) q.push(i);
	
	while(!q.empty()){
		int u = q.front(); q.pop();
		vis[u] = 1;
		for (int i = h[u]; ~i; i = ne[i]){
			int v = e[i];
			d[v] --;
			if (d[v] == 1) q.push(v);
		}
	}
	
	for (int i = 1; i <= n; i ++ ) if (vis[i] == 0) loop.push_back(i), jud[i] = 1;   // 将换中的节点 压入栈, 并标记一下
}

void dfs(int u, int f){    // 以环中有向外连接的结点为根 记录 子树大小
//	s[u] = 1;
	for (int i = h[u]; ~i; i = ne[i]){
		int v = e[i];
		if (jud[v] || v == f) continue;  // 
		dfs(v, u);
		s[f] += s[v];
	}
}

int main (){
	
	int T;
	cin >> T;
	while (T -- ){
	
		cin >> n;
		// 初始化  莫忘记
		for (int i = 0; i<= n; i ++ ) h[i] = -1, d[i] = 0, jud[i] = 0; 
		cnt = 0;
		loop.clear();
		for (int i = 0;  i<= n; i ++ ) s[i] = 1;
		
		for (int i = 0, u, v; i < n; i ++ ){
			scanf ("%d%d", &u, &v);
			add(u, v);
			add(v, u);
			d[u] ++, d[v] ++;
		}
		
		topsort();
		LL ans = 1ll * n * (n - 1);
		for (int i = 0; i < loop.size(); i ++ ){
			int u = loop[i];
			dfs(u, u);
			ans -= (s[u] * (s[u] - 1) / 2ll);
		}
		printf ("%lld\n", ans);	
		
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值