题意:给你一张n个点m条边的图,问你经过其中m-2条边两次,剩下2条边一次的方案数有几种,如果剩下两条边的集合一样算同一种
题解:把题意转换成,我们挑选两条边,把其他的边都变成两条,这样就变成了一笔画问题(欧拉路径是否存在),我们欧拉路径存在的充要条件是奇点个数是0或2,。然后下面需要进行分类讨论,我们把边分成普通变和自环(u=v)两类。
1.选取两条不相邻普通边,图中存在4个奇点,不满足欧拉路径条件
2.选取两条相邻普通边,图中存在2个奇点,满足欧拉路径条件
3.选取一条普通边一条自环,图中存在2个奇点,满足欧拉路径条件
4.选取两条自环,图中存在0个奇点,满足欧拉路径条件
在这之前如果m条边覆盖的集合不是连通的,答案为0
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 100;
typedef long long ll;
vector<int>vec[N];
int a[N],fa[N],vis[N];
int deg[N];
int find(int x)
{
int r=x;
while(fa[r]!=r) r=fa[r];
int i=x,j;
while(i!=r) {
j=fa[i];
fa[i]=r;
i=j;
}
return r;
}
int main()
{
ios::sync_with_stdio(false);
int n,m,i,j,u,v;
int fx,fy;
ll loop,ans,edge;
cin>>n>>m;
loop=ans=edge=0;
for(i=1;i<=n;i++) fa[i]=i;
while(m--) {
cin>>u>>v;
vis[u]=vis[v]=1;
if(u==v) {
loop++;
continue;
}
edge++;
vec[u].push_back(v);
vec[v].push_back(u);
deg[u]++;
deg[v]++;
fx=find(u);
fy=find(v);
if(fx!=fy) fa[fx]=fy;
}
for(j=1;j<=n;j++)
if(vis[j]) break;
for(i=1;i<=n;i++)
if(vis[i] && find(i)!=find(j)) break;
if(i<=n) {
printf("0\n");
}
else {
for(i=1;i<=n;i++) {
ans+=(ll) deg[i]*(deg[i]-1)/2;
}
ans+=(ll)loop*edge;
ans+=(ll) loop*(loop-1)/2;
cout<<ans<<endl;
}
return 0;
}