题意
给定 n 个城市 m 条无向路(无向路存在自环的情况),问能够找到多少条不同的路径,使得其中 m-2 条路径被走过 2 次,剩下 2 条路径被走过 1 次。
两条路径被视为不同的,当且仅当走过走过 1 次的两条路不同。
分析
该题不考虑一定要经过所有点,仅需考虑都过 m-2 条路 2 次,剩下 2 条路 1 次即可。
无向图存在欧拉路当且仅当它是连通的,且除了恰好两个顶点外,其余所有顶点的度为偶数。
考虑 m 条路都需要经过两次的情况,可视作是原图中直接相连的两点当前存在两条相同的边,故图中所有点的度数必为偶数,则欧拉路径一定存在。此时,要求从上述 2*m 条边中删去两端点不同的两边。
- 若该两边没有公共端点,必然导致此时 2*m 条边的图中有 4 个点(该两边的端点)的度为奇数,即不存在欧拉路
故要删去的两边必然存在公共端点,即计算每个点的度为 cnti ,则每个连通图中的点对答案的贡献为 C2cnti 。
上述考虑的是没有自环的情况,当存在自环时:
- 删除两个自环边,由于自环边两端连接同一点,故不会对连通图中点的度奇偶性产生影响。对答案的贡献为 C2loop ,记自环边的条数为 loop 。
- 删除一个自环边和一条非自环边,此时连通图中产生 2 个点的度为奇数,仍存在欧拉路径。该情况有 loop×(m−loop) 种。
至于判断图的连通性,可以考虑使用 并查集 或者 搜索 等方案都可;对于不连通的图,显然,必然不存在欧拉路径。
代码
#include<bits/stdc++.h>
using namespace std;
const int V = 1e6 + 10;
int n, m, fa[V];
long long loop, cnt, deg[V];
int find(int x) { return fa[x] = fa[x] == x ? x : find(fa[x]); }
void Union(int u, int v) {
int fx = find(u), fy = find(v);
fa[fx] = fy;
}
set<int> st;
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
fa[i] = i;
for(int i=0, u, v;i<m;i++)
{
scanf("%d %d",&u,&v);
if(u == v) loop++;
else deg[u]++, deg[v]++;
st.insert(u), st.insert(v);
Union(u, v);
}
long long ans = 0;
for(set<int>::iterator it=st.begin();it!=st.end();it++)
{
if(find(*it) != find(*st.begin())) {
printf("0\n");
return 0;
}
ans += deg[*it] * (deg[*it]-1) / 2;
}
ans += loop * (loop-1) / 2;
ans += loop * (m-loop);
printf("%I64d\n", ans);
}