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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Summer_via/article/details/69665219

题意

给定一个无重边的图(有自环),求有多少路径满足路径遍历所有的边,并且有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;
}


猜你喜欢

转载自blog.csdn.net/Summer_via/article/details/69665219