游历校园 [COGS 614] [欧拉图]
Description
刷完牙洗完脸,黄黄同学就要上课去了。可是黄黄同学每次去上课时总喜欢把校园里面的每条路都走一遍,当然,黄黄同学想每条路也只走一遍。我们一般人很可能对一些地图是办不到每条路走一遍且仅走一遍的,但是黄黄同学有个传送机,他可以任意地将一个人从一个路口传送到任意一个路口。
可是,每传送一次是需要耗费巨大的内力的,黄黄同学希望可以用最少的传送次数完成游遍校园,你能帮助他吗 ?
因为黄黄同学只是游历校园,于是我们可以认为黄黄同学可以从任意点开始,到任意点结束。
Input
第一行有一个整数 N ,表示黄黄的校园里一共有多少路口。
第二行有一个整数 M ,表示路口之间有 M 条路。
后面 M 行每行两个整数 a 、 b 表示 a 与 b 之间有一条路,且路是双向的。
Output
只包括一个整数 s ,表示黄黄同学最少的传送次数。
Sample Input
3
2
1 2
2 3
Sample Output
0
Hint
数据范围:
对于 100 %的数据,保证 N ≤ 100000 , K ≤ 500000 , 1 ≤ a , b ≤ N 。
Solution
请教了数学组的大佬后才会做的...
对于一个连通块,要完成「一笔画」,度数为寄的点只能为0或2个,而跳一次相当于连一条边。消除两个寄点
所以当一个连通块寄点数为x>2时,要化成2个时,加的边(跳的次数)=(x-2)/2
所以bfs解决连通块就行了
但是注意!无度数的点不要考虑,因为没有边要遍历。
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<queue> 2 #include<vector> 3 #include<cstdio> 4 #include<cstring> 5 #include<iostream> 6 #include<algorithm> 7 #define RG register int 8 #define rep(i,a,b) for(RG i=a;i<=b;i++) 9 #define per(i,a,b) for(RG i=a;i>=b;i--) 10 #define add(x,y) e[++cnt].v=y,e[cnt].next=head[x],head[x]=cnt 11 #define inf (1<<30) 12 #define maxn 100005 13 #define maxm 500005 14 using namespace std; 15 int n,m,sid,cnt,ans; 16 int head[maxn],vis[maxn],deg[maxn]; 17 vector<int> vec[maxn]; 18 struct E{ 19 int v,next; 20 }e[maxm<<1]; 21 inline int read() 22 { 23 int x=0,f=1;char c=getchar(); 24 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 25 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 26 return x*f; 27 } 28 29 void bfs(int x) 30 { 31 int sum=0; 32 queue<int> que; 33 que.push(x),vis[x]=1; 34 RG u,v; 35 while(!que.empty()) 36 { 37 u=que.front(),que.pop(); 38 if(deg[u]&1) ++sum; 39 for(RG i=head[u];i;i=e[i].next) 40 { 41 v=e[i].v; 42 if(!vis[v]) 43 vis[v]=1,que.push(v); 44 } 45 } 46 if(sum>2) ans+=(sum-2)>>1; 47 } 48 49 int main() 50 { 51 52 n=read(),m=read(); 53 RG u,v;rep(i,1,m) u=read(),v=read(),add(u,v),add(v,u),++deg[u],++deg[v]; 54 rep(i,1,n) if(!vis[i]&°[i]>0) bfs(i),ans++; 55 cout<<ans-1; 56 return 0; 57 }