【题解】洛谷 CF788B Weird journey


题目

原题链接

问题描述

总共有 n n n 个节点, m m m 条路径,要求其中 m − 2 m-2 m2 条路径走两遍,剩下 2 2 2 条路径仅走一遍,问不同的路径总数有多少,如果仅走一遍的两条边不同则将这两条路径视为不同。

输入格式

  • 第一行两个整数n和m,表示图有n个节点m条边,数据保证不存在重边
  • 接下来m行,每行两个整数u,v,表示节点u和节点v之间有一条无向边

输出格式

  • 一个整数,表示方案数

数据范围

1 ≤ n , m ≤ 1 × 1 0 6 1\le n,m\le 1\times10^6 1n,m1×106

输入/输出例子

输入

5 4
1 2
1 3
1 4
1 5

输出

6

提示

在这里插入图片描述


解题思路

分析

考虑直接将每条边都当作两条边,那么题意及从 2 n 2n 2n 条边任选 2 2 2 条不是连接相同节点的边删除后图存在欧拉路,求删边的方案数。

如果本来的图不连通,那么肯定没有合适的方案,直接输出 0 0 0 就可以了。

否则我们在分析:由于我们是将每条边当作两条边的,那么对于建的图来说,每个顶点的度数为偶数,及一定存在欧拉路。

那么就来考虑删的边了。

我们可以把边分为自环和非自环两类。

为什么呢?

因为自环只跟一个顶点有关系,而非自环跟两个顶点有关系。
如果删除了一个自环,那剩下的所有点的度数仍然为偶数,所以可以随意删除下一条边。
而对于删除的第二条边,如果是非自环,那么图就有两个积点,存在欧拉路径,如果是自环,那么图所有点为偶点,存在欧拉回路。

所以可以得出自环的贡献为:
c n t × ( m − c n t ) + c n t × ( c n t − 1 ) / 2 cnt \times (m-cnt)+cnt\times (cnt-1)/2 cnt×(mcnt)+cnt×(cnt1)/2
其中 c n t cnt cnt 为自环数, m m m 是边数。

如果删除两条非自环,如果可行,那么它们一定共顶点,只有这样才会使共顶点的度数 − 2 -2 2,仍为偶点,两外两个点的度数 − 1 -1 1,为积点,存在欧拉路径。

所以非自环的贡献为:
∑ i = 1 n l i × ( l i − 1 ) 2 \sum_{i=1}^{n}\frac{l_i\times(l_i-1)}{2} i=1n2li×(li1)
其中 l i l_i li 为每个顶点连接的边数(不包括自环)。

Code

#include<bits/stdc++.h>
#define int long long
const int N=1e6+1;
using namespace std;
vector<int>E[N];
int n,m,x[N],y[N],deg[N],ans,vis[N],cnt,fa[N];
inline int ga(int x)
{
	return x==fa[x]?fa[x]:fa[x]=ga(fa[x]);
}
inline void uni(int x,int y)
{
	int fx=ga(x),fy=ga(y);
	if(fx!=fy)
		fa[fx]=fy;
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL),cout.tie(NULL);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		cin>>x[i]>>y[i];
		uni(x[i],y[i]);
		if(x[i]==y[i])
			cnt++;
		else
			E[x[i]].push_back(y[i]),E[y[i]].push_back(x[i]);
	}
	for(int i=2;i<=m;i++)
		if(ga(x[i])!=ga(x[1]))
			cout<<"0",exit(0);
	for(int i=1;i<=n;i++)
	{
		int le=E[i].size();
		ans+=le*(le-1)/2;
	}
	ans+=cnt*(cnt-1)/2;
	ans+=cnt*(m-cnt);
	cout<<ans;
	return 0;
}

更多方法

更多方法

  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值