题目:点击打开链接
题意: 一笔画问题,有n个城镇,m条路,路把城镇连接起来,问需要多少人能把所有路走完(如果有孤立城镇,忽略),这就转换为一笔画问题,问需要几笔可以把路走完:
分析:
如果是个欧拉回路一笔就可以完成,如果是个其它连通集,要根据这个集合的奇度数而定,笔划数=奇度数/2,用并查集来判断有多少个连通集,然后用vector来存这些连通集,通过判断度数是奇偶性来确定是否为欧拉回路;总之笔划数 = 奇度数/2 + 欧拉回路数;
odd数组存储连通路的奇数点,vis数组判断vector中是否已经有这个连通图,degree是点的度;
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
const int maxn=100005;
int m,n,fa[maxn],degree[maxn],vis[maxn],odd[maxn];
vector<int>v;
int findfa(int x)
{
while(x!=fa[x])
x=fa[x];
return x;
}
int main()
{
while(cin>>n>>m){
for(int i=1;i<=n;i++)
fa[i]=i;
memset(degree,0,sizeof(degree));
memset(vis,0,sizeof(vis));
memset(odd,0,sizeof(odd));
v.clear();
int a,b;
for(int i=0;i<m;i++){
cin>>a>>b;
int x=findfa(a);
int y=findfa(b);
degree[a]++;
degree[b]++;
fa[x]=y;
}
for(int i=1;i<=n;i++){
int f=findfa(i);
if(!vis[f]){
v.push_back(f);
vis[f]=1;
}
if(degree[i]&1)
odd[f]++;
}
int sum=0;
for(int i=0;i<v.size();i++){
int k=v[i];
if(degree[k]==0)continue;
if(odd[k]==0)sum++;
else sum+=odd[k]/2;
}
cout<<sum<<endl;
}
return 0;
}