CF788B Weird journey 题解

题意描述

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

输入输出样例

输入 #1

5 4
1 2
1 3
1 4
1 5

输出 #1

6

输入 #2

5 3
1 2
2 3
4 5

输出 #2

0

输入 #3

2 2
1 1
1 2

输出 #3

1

分析

根据题目中的信息大概可以想到用欧拉路。

我们可以把一条边看成两条,问题转化为删去两条不同的边,使原图中存在欧拉回路

首先,如果图是不联通的,那么直接输出 \(0\) 即可

如果图是联通的

那么存在欧拉回路的条件是所有点的度数为偶数或者只有两个点的度数为奇数

那么我们就有以下三种方案

1、删去两个自环

2、删去一个自环和任意一条边

3、删去一个节点所连接的两条边

注意开 \(long\ long\)

代码

#include<cstdio>
#define int long long
inline int read(){
	int x=0,fh=1;
	char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=3e6+5;
int n,m,rd[maxn],cntt,cnt[maxn],fa[maxn],anss[maxn];
long long ans=0;
int zhao(int xx){
	if(xx==fa[xx]) return xx;
	return fa[xx]=zhao(fa[xx]);
}
void bing(int xx,int yy){
	fa[zhao(xx)]=zhao(yy);
}
signed main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	for(int i=1;i<=m;i++){
		int aa,bb;
		aa=read(),bb=read();
		if(aa==bb){
			cnt[aa]++;
			cntt++;
			continue;
		}
		bing(aa,bb);
		rd[aa]++;
		rd[bb]++;
	}
	for(int i=1;i<=n;i++){
		anss[zhao(i)]+=rd[i];
		anss[zhao(i)]+=cnt[i]*2;
	}
	for(int i=1;i<=n;i++){
		if(anss[i]==0 || anss[i]==m*2) continue;
		printf("0\n");
		return 0;
	}
	for(int i=1;i<=n;i++){
		if(rd[i]>=2){
			ans+=1LL*(rd[i]-1)*rd[i]/2LL;
		}
	}
	ans+=cntt*(m-cntt);
	ans+=1LL*(cntt-1)*cntt/2LL;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-10-07 16:14  liuchanglc  阅读(163)  评论(0编辑  收藏  举报