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;
}
完结撒花