Codeforces Round #407 (Div. 1) B. Weird journey

来源:互联网 发布:历史上纪晓岚 知乎 编辑:程序博客网 时间:2024/05/19 14:19

题意

给定一个无重边的图(有自环),求有多少路径满足路径遍历所有的边,并且有m-2条边被遍历两次,2条边被遍历一次,两条路路径不同的定义是两条路径遍历边的集合不同?

思路

遍历所有的边,想到欧拉回路,即一笔画问题,一笔画有两种情况:(1)有且仅有两个节点的度数为奇数(2)所有节点的度数均为偶数,题目要求m-2条边都遍历两次,
不如先将所有的边当作二重边,那么所有节点的度数都将翻倍,度数都变成了偶数,有两条边只遍历一次,即把这两条所连接的节点的度数减去1。假如减去度数后仍然能满足欧拉图的要求,有三种情况:
(1)两条只遍历一次的边(下称‘’两条边‘’)为两条相邻的非自环边
(2)两条边为一个自环和任意一条非自环边
(3)两条不同的自环边
此外还要,判定所有边是否都能被遍历,与连通图的判定类似。

代码

#include<bits/stdc++.h>using namespace std;int n,m;vector<int>G[1000006];int d[1000006];bool vis[1000006];int cnt;void dfs(int p){    cnt++;    for(int i=0;i<G[p].size();i++)    {        int to=G[p][i];        if(!vis[to]) vis[to]=1,dfs(to);    }}int main(){    while(~scanf("%d%d",&n,&m))    {        for(int i=0;i<1000000;i++) G[i].clear();        memset(d,0,sizeof d);        memset(vis,1,sizeof vis);        long long ans=0;        int num=0;        for(int i=0;i<m;i++)        {            int u,v;            scanf("%d %d",&u,&v);            G[u].push_back(v);            G[v].push_back(u);            vis[u]=vis[v]=0;            if(u!=v)ans+=d[u]+d[v],d[u]++,d[v]++;            else num++;        }        ans+=1ll*num*(num-1)/2+1ll*num*(m-num);        for(int i=1;i<=n;i++) if(!vis[i]) {vis[i]=0;dfs(i);break;}        int cnt=0;        for(int i=1;i<=n;i++) if(vis[i]) cnt++;        if(cnt==n) printf("%I64d\n",ans);        else puts("0");    }    return 0;}


0 0