5、传送机(sent.*)

问题描述:

黄黄同学要到清华大学上学去了。黄黄同学很喜欢清华大学的校园,每次去上课时总喜欢把校园里面的每条路都走一遍,当然,黄黄同学想每条路也只走一遍。
我们一般人很可能对一些地图是办不到每条路走一遍且仅走一遍的,但是黄黄同学有个传送机,他可以任意地将一个人从一个路口传送到任意一个路口。
可是,每传送一次是需要耗费巨大的内力的,黄黄同学希望可以用最少的传送次数完成游遍校园,你帮助他吗?因为黄黄同学只是游历校园,于是我们可以认为黄黄同学可以从任意点开始,到任意点结束。
注意:不必经过所有的点。输入格式:输入第一行一个整数N,表示黄黄的校园里一共有多少路口。第二行一个整数M,表示路口之间有M条路。后面M行,每行两个整数a、b,表示a与b之间有一条路,且路是双向的。输出格式:输出一行一个整数S,表示黄黄同学最少的传送次数。

输入样例:

3
2
1 2
2 3

输出样例:

0

数据规模:

对于100%的数据满足:N<=100000,M<=500000,1<=a,b<=N。


知识储备:

奇点:度数为奇数的点 //度数是什么就不解释了

当一个连通图的奇点个数为0或2时,该连通图可以从某个点出发,经过每条边一次(仅一次)//自己概括,可能有所疏忽,请大家指出错误之处!

一句话概括,就是添加最少的边,使它构成一个欧拉回路,也就是广为人知的一笔画问题。

这样理解,你就死了因为根据之前我的题解,会导致细节贼多,超难理解,所以我换了种思路

可以这样考虑:不要看总体,考虑每个连通块分别构成欧拉回路,也就是对于每个连通块,连上 max((奇点个数 - 2) / 2,0)条边

再将所有连通块的起点和终点顺次相连,这样就可以保证整个图构成欧拉回路了

不难理解吧(由于目前时间紧迫,有时间再添加具体细节)

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

int N, M;
int fa[MAXN];
int s[MAXN], a[MAXN];

int find( int x ){
    if ( x == fa[x] ) return x;
    return fa[x] = find( fa[x] );
}

void Merge( int x, int y ){
    x = find(x); y = find(y);
    if ( x != y ) fa[x] = y;
}

int main(){
    scanf( "%d%d", &N, &M );
    if ( M == 0 ){ printf( "0\n" ); return 0; }
    for ( int i = 1; i <= N; ++i ) fa[i] = i;
    for ( int i = 1; i <= M; ++i ){
        int x, y; scanf( "%d%d", &x, &y );
        s[x]++; s[y]++;
        Merge( x, y );
    }
    for ( int i = 1; i <= N; ++i ) a[find(i)] += s[i] % 2;
    int ans(0);
    for ( int i = 1; i <= N; ++i )
        if ( s[i] > 0 && find(i) == i ) ans = ans + 1 + max( 0, ( a[i] - 2 ) / 2 );
    printf( "%d\n", ans - 1 );
    return 0;
}

完结撒花