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; }
AC代码二(156ms):
#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; }
AC代码三(78ms):
#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; }
以上代码只是在计算每个连通分量要几笔画 的实现方法不同
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-25 11:17:10