hdoj 3018 Ant Trip(无向图欧拉路||一笔画+并查集)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3018

思路分析:题目可以看做一笔画问题,求最少画多少笔可以把所有的边画一次并且只画一次;

首先可以求出该无向图中连通图的个数,在每个无向连通图中求出需要画的笔数再相加即为所求。在一个无向连通图中,如果所有的点的度数为偶数则存在一个欧拉回路,

则只需要画一笔即可;如果图中存在度数为奇数的点,则需要画的笔数为度数为奇数的点的个数 /2;需要注意的孤立的点不需要画;

 

代码如下:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int MAX_N = 100000 + 100;
int fa[MAX_N], odd[MAX_N];
int link[MAX_N], set_count[MAX_N];

void Init()
{
    for (int i = 0; i < MAX_N; ++i)
    {
        set_count[i] = 1;
        fa[i] = i;
    }
}

int Find(int num)
{
    if (fa[num] == num)
        return num;
    else
        return fa[num] = Find(fa[num]);
}

int Union(int a, int b)
{
    int fa_a = Find(a);
    int fa_b = Find(b);

    if (fa_a == fa_b)
        return -1;
    else if (fa_a > fa_b)
    {
        fa[fa_b] = fa_a;
        set_count[fa_a] += set_count[fa_b];
    }
    else
    {
        fa[fa_a] = fa_b;
        set_count[fa_b] += set_count[fa_a];
    }
    return 1;
}

int main()
{
    int vertex_num, road_num;
    int ver_1, ver_2;

    while (scanf("%d %d", &vertex_num, &road_num) != EOF)
    {
        int ans = 0;

        Init();
        memset(link, 0, sizeof(link));
        memset(odd, 0, sizeof(odd));
        for (int i = 0; i < road_num; ++i)
        {
            scanf("%d %d", &ver_1, &ver_2);
            link[ver_1]++;
            link[ver_2]++;
            Union(ver_1, ver_2);
        }
        for (int i = 1; i <= vertex_num; ++i)
        {
            int fa = Find(i);
            if ((link[i] & 1) == 1)
                odd[fa]++;
        }
        for (int i = 1; i <= vertex_num; ++i)
        {
            if (fa[i] == i && set_count[i] != 1)
            {
                if (odd[i] == 0)
                    ans++;
                else
                    ans += odd[i] / 2;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
posted @ 2015-07-23 21:19  Leptus  阅读(336)  评论(0编辑  收藏  举报