题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3018
题目大意:给出一个图,问几笔画才能经过所有边。

思路:就是求图的欧拉路径的数量:

对于一个连通子图(连通块)

1:孤立点:不用画
2:是欧拉图,具有欧拉回路:ans++;
3:不是欧拉图,(那么奇数点的数量一定是奇偶数个:离散数学:握手定理)ans=奇数点/2

并查集维护连通块(开始以为要dfs染色维护连通块,但是并查集在输入边就维护好了,非常好用啊!)

#include <bits/stdc++.h>
using namespace std;

int a[100005];
int d[100005];
vector<int> k;
bool vis[100005];
int s[100005];

int fd(int x)
{
    if(a[x]<0)
    {
        return x;
    }

    return a[x]=fd(a[x]);
}

void L(int x, int y)
{
    x=fd(x), y=fd(y);
    if(x!=y)
    {
        a[x]=y;
    }
}

int main()
{
    int n, m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)
        {
            a[i]=-i;
        }
        int u, v;
        k.clear();
        memset(s, 0, sizeof(s));
        memset(vis, 0, sizeof(vis));
        memset(d, 0, sizeof(d));
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            L(u, v);
            d[u]++, d[v]++;
        }

        for(int i=1;i<=n;i++)
        {
            int v=fd(i);
            if(!vis[v])
            {
                k.push_back(v);//并查集的根v代表这个连通块
                vis[v]=1;
            }
            if(d[i]%2==1)//度数为奇数
            {
                s[v]++;
            }
        }
        int ans=0;
        for(int i=0;i<k.size();i++)
        {
            int v=k[i];
            if(d[v]==0)//孤立点
            {
                continue;
            }
            if(s[v]==0)//欧拉回路
            {
                ans++;
            }
            else
            {
                ans+=s[v]/2;
            }
        }
        printf("%d\n", ans);
    }

    return 0;
}