1. 程式人生 > >Codeforces Round #407 (Div. 1) B. Weird journey

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

題意

給定一個無重邊的圖(有自環),求有多少路徑滿足路徑遍歷所有的邊,並且有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;
}