标签:并查集
1.题意:给一个无向简单图,问至少几笔画画完所有的边。
2.思路:①先用并查集求出有几个连通分量;②如果连通分量中只有一个结点,那么就是0笔画;③在一个简单无向连通图中,如果没有欧拉回路,至少要用n/2笔画画完所有边,n是奇点个数。
3AC代码一(93ms):
#include<cstdio>
#include<cstring>
#include<set>
#include<vector>
using namespace std;
int n,m;
int father[100005];
int deg[100005];//每个结点的度
int vis[100005];
int odd_cnt[100005];
vector<int> vec;
int Find(int a)
{
int r=a;
while(father[a]!=a)
{
a=father[a];
}
father[r]=a;
return a;
}
inline void Union(int a,int b)
{
a=Find(a);
b=Find(b);//千万不要写成father[b]啊啊啊!!!!!!!!!!!!!!!!1
if(a!=b)
{
father[b]=a;
}
}
int main()
{
int ans;
while(scanf("%d%d",&n,&m)==2)
{
ans=0;
vec.clear();
for(int i=1; i<=n; i++)
{
father[i]=i;
deg[i]=0;
vis[i]=0;
odd_cnt[i]=0;
}
for(int i=0; i<m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
deg[a]++;
deg[b]++;
Union(a,b);
}
for(int i=1; i<=n; i++)
{
father[i]=Find(i);
if(vis[father[i]]==0)
{
vec.push_back(father[i]);
vis[father[i]]=1;
}
if(deg[i]%2)
odd_cnt[father[i]]++;
}
for(int i=0;i<vec.size();i++)
{
int f=vec[i];
if(deg[f]==0)
continue;
if(odd_cnt[f]==0)
ans=ans+1;
else
ans=ans+odd_cnt[f]/2;//在一个简单无向连通图中,如果没有欧拉回路,至少要用n/2笔画画完所有边,n是奇点个数
}
printf("%d\n",ans);
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
struct Node
{
int num;
set<int> st;
void init()
{
num=0;
st.clear();
}
};
int n,m;
int father[100005];
Node son[100005];//结点i的儿子的个数son[i].num,然后装在集合st里
int deg[100005];//每个结点的度
int Find(int a)
{
int r=a;
while(father[a]!=a)
{
a=father[a];
}
father[r]=a;
return a;
}
void Union(int a,int b)
{
a=Find(a);
b=Find(b);
if(a!=b)
{
father[b]=a;
}
}
int main()
{
int ans;
while(scanf("%d%d",&n,&m)==2)
{
ans=0;
for(int i=1; i<=n; i++)
{
father[i]=i;
//son[i]=0;
deg[i]=0;
son[i].init();
}
for(int i=0; i<m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
deg[a]++;
deg[b]++;
Union(a,b);
}
for(int i=1; i<=n; i++)
{
father[i]=Find(i);
son[father[i]].num++;
son[father[i]].st.insert(i);
}
for(int i=1; i<=n; i++)
{
if(son[i].num>=2)
{
set<int>::iterator it;
int cnt=0;
for(it=son[i].st.begin(); it!=son[i].st.end(); it++)
{
if(deg[*it]%2)
cnt++;
}
if(!cnt)
ans+=1;
else
ans=ans+cnt/2;//在一个简单无向连通图中,至少要用n/2笔画画完所有边,n是奇点个数
}
}
printf("%d\n",ans);
}
return 0;
}
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
struct Node
{
int son_num;
int odd_son_num;
void init()
{
son_num=0;
odd_son_num=0;
}
};
int n,m;
int father[100005];
Node son[100005];//结点i的奇点儿子的个数son[i]
int deg[100005];//每个结点的度
int Find(int a)
{
int r=a;
while(father[a]!=a)
{
a=father[a];
}
father[r]=a;
return a;
}
inline void Union(int a,int b)
{
a=Find(a);
b=Find(b);
if(a!=b)
{
father[b]=a;
}
}
int main()
{
int ans;
while(scanf("%d%d",&n,&m)==2)
{
ans=0;
for(int i=1; i<=n; i++)
{
father[i]=i;
//son[i]=0;
deg[i]=0;
son[i].init();
}
for(int i=0; i<m; i++)
{
int a,b;
scanf("%d%d",&a,&b);
deg[a]++;
deg[b]++;
Union(a,b);
}
for(int i=1; i<=n; i++)
{
father[i]=Find(i);
son[father[i]].son_num++;
if(deg[i]%2)
son[father[i]].odd_son_num++;
}
for(int i=1;i<=n;i++)
{
if(son[i].son_num>=2)
{
if(!son[i].odd_son_num)
ans+=1;
else
ans=ans+son[i].odd_son_num/2;//在一个简单无向连通图中,至少要用n/2笔画画完所有边,n是奇点个数
}
}
/*for(int i=1; i<=n; i++)
{
if(son[i].num>=2)
{
// printf("%d\n",son[i].num);
set<int>::iterator it;
int cnt=0;
for(it=son[i].st.begin(); it!=son[i].st.end(); it++)
{
//printf("%d\n",*it);
if(deg[*it]%2)
cnt++;
}
if(!cnt)
ans+=1;
else
ans=ans+cnt/2;//在一个简单无向连通图中,至少要用n/2笔画画完所有边,n是奇点个数
}
}*/
printf("%d\n",ans);
}
return 0;
}
以上代码只是在计算每个连通分量要几笔画 的实现方法不同
版权声明:本文为博主原创文章,未经博主允许不得转载。
hdu 3018Ant Trip(一笔画问题,用并查集就无向图的连通分量)
标签:并查集
原文地址:http://blog.csdn.net/xky1306102chenhong/article/details/47045815