HDU 3018 Ant Trip【欧拉回路】【经典一笔画问题】

Ant Trip

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4850 Accepted Submission(s): 1907

Problem Description

Ant Country consist of N towns.There are M roads connecting the towns.

Ant Tony,together with his friends,wants to go through every part of the country.

They intend to visit every road , and every road must be visited for exact one time.However,it may be a mission impossible for only one group of people. So they are trying to divide all the people into several groups,and each may start at different town.Now tony wants to know what is the least groups of ants that needs to form to achieve their goal.

Input

Input contains multiple cases.Test cases are separated by several blank lines. Each test case starts with two integer N(1<=N<=100000),M(0<=M<=200000),indicating that there are N towns and M roads in Ant Country.Followed by M lines,each line contains two integers a,b,(1<=a,b<=N) indicating that there is a road connecting town a and town b. No two roads will be the same,and there is no road connecting the same town.

Output

For each test case ,output the least groups that needs to form to achieve their goal.

Sample Input

3 3
1 2
2 3
1 3

4 2
1 2
3 4

Sample Output

1
2

Hint

New ~~~ Notice: if there are no road connecting one town ,tony may forget about the town.
In sample 1,tony and his friends just form one group,they can start at either town 1,2,or 3.
In sample 2,tony and his friends must form two group.

题意: 给你一个图,以及一些边,问你需要多少个人可以走完所有的边, 类似于一笔画。

分析:
思路:
常规题的思路,我们还可以发现在一个集合中如果存在奇点, 那么在这个集合中需要 (奇点个数 / 2) 笔 即可画完,因为一个集合中奇点的个数始终为偶数,所以直接统计整个图中的奇点个数即可, (代码里面的t) 还有考虑集合中不存在奇点的集合,这种情况的只需要一笔即可(也就是里面的sum)

ps:还有一个思路就是不用set统计每个集合中的具体元素,只需要标记下那些奇点所在的集合(标记下根节点即可),然后在最后只需统计没有标记的根节点 这里注意一定要check 孤立的点!

参考代码

#include

using namespace std;

const int maxn = 1e5 + 10;


/***
    一笔画问题,给你一个图,让你判断最少需要几笔画完,孤立的点不用画。


    思路:我们还可以发现在一个集合中如果存在奇点,
    那么在这个集合中需要   (奇点个数 / 2)  笔 即可画完,
    因为一个集合中奇点的个数始终为偶数,所以直接统计整个图中的
    奇点个数即可,  (代码里面的t)
    还有考虑集合中不存在奇点的集合,这种情况的只需要一笔即可(也就是里面的sum)


    ps:还有一个思路就是不用set统计每个集合中的具体元素,只需要标记下那些
    奇点所在的集合(标记下根节点即可),然后在最后只需统计没有标记的根节点
    这里注意一定要check 孤立的点!

*/


/**
    f : 并查集中,存储 i个节点的父亲节点
    e : 存储每个集合
    len : 每个节点的 入度+出度
*/

int f[maxn];
set<int> e[maxn];
int len[maxn];

void init() {
    for (int i = 0; i < maxn; i++){
        f[i] = i;
        e[i].clear();
        len[i] = 0;
    }
}

int fa(int x) {
    return x == f[x] ? x : f[x] = fa(f[x]);
}

int main(){
    int n,m;
    while (scanf("%d%d", &n, &m) != -1) {
        init();
        for (int i = 0; i < m; i++) {
            int x, y; scanf("%d%d", &x, &y);
            len[x]++,len[y]++;
            int fx = fa(x);
            int fy = fa(y);
            f[fx] = fy;
        }
        int t = 0;
        for (int i = 1; i <= n; i++) {
            f[i] = fa(i);
            if (len[i] & 1) t++;
        }
        for (int i = 1; i <= n; i++) e[f[i]].insert(i);
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            if (e[i].size() > 2) { /// 这里注意check
                int odd = 0;
                for (auto it : e[i]) if (len[it] & 1) odd++;
                if (!odd) sum++;
            }
        }
        cout << sum + t / 2<< endl;
    }
    return 0;
}

你可能感兴趣的:(----,图论,----)