欧拉回路,欧拉路径(收录
题意:
欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const ll mod=998244353; const int INF= 0x3f3f3f3f; const int N=2e5+5; int n,m; int du[1005]; int f[1005]; int getf(int x) { if(x!=f[x]) { f[x]=getf(f[x]); } return f[x]; } int main() { int a,b,fa,fb; while(cin>>n && n) { cin>>m; int cnt=0; mem(f,0); mem(du,0); for(int i=0;i<=n;i++) f[i]=i; while(m--) { cin>>a>>b; du[a]++; du[b]++; fa=getf(a); fb=getf(b); if(fa!=fb) { f[fa]=fb; } else cnt++; //如果fa==fb,则两个节点在同一并查集中, //这样的情况有且只能出现一次 ,否则走的路径会存在重复 } if(cnt!=1) { cout<<0<<endl; continue; } int flag=0; for(int i=1;i<=n;i++) { if(du[i]%2!=0){ flag=1; break; } } cout<< (flag? 0:1)<<endl; } }
题意:
求无向图每条边恰好经过两次,在回到原点,输出经过的顶点。容易转化为有向图欧拉回路每条边经过一次。
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const ll mod=998244353; const int INF= 0x3f3f3f3f; const int N=2e5+5; int n,m,cnt=0; int ans[200005]; struct edge { int to,flag; edge(int _to,int _flag):to(_to),flag(_flag){} }; vector<edge> v[200005]; void dfs(int x) { for(int i=0;i<v[x].size();i++) { if(v[x][i].flag==0) { v[x][i].flag=1; dfs(v[x][i].to); } } ans[++cnt]=x; } int main() { int a,b; cin>>n>>m; while(m--) { scanf("%d%d",&a,&b); v[a].push_back(edge(b,0)); v[b].push_back(edge(a,0)); } dfs(1); //printf("1\n"); for(int i=1;i<=cnt;i++) printf("%d\n",ans[i]); return 0; }
题意:
给你无向图的N个点和M条边,保证这M条边都不同且不会存在同一点的自环边,现在问你至少要几笔才能所有边都画一遍.(一笔画的时候笔不离开纸)
思路:
(1)如果该连通分量是一个孤立的点,即num[i]==0或num[i]==1的时候,注意num[i]==0表示i不是根节点,num[i]==1表示的是独立的点。
(2)如果该连通分量是欧拉图或半欧拉图,那么只需要1笔即可,即num[i]>1且sum[i]==0的时候,表示是(半)欧拉图。
(3)如果该连通分量不是一个欧拉图时,那么我们需要奇数度点个数/2,即num[i]>1且sum[i]>0时需要sum[i]/2笔。
#include<iostream> #include<cstdio> #include <cctype> #include<algorithm> #include<cstring> #include<cmath> #include<string> #include<cmath> #include<set> #include<vector> #include<stack> #include<queue> #include<map> using namespace std; #define ll long long #define mem(a,x) memset(a,x,sizeof(a)) #define se second #define fi first const ll mod=998244353; const int INF= 0x3f3f3f3f; const int N=2e5+5; int n,m; int du[N],f[N],num[N],sum[N]; //num[i]表示祖宗节点为i的并查集内有多少个节点 //sum[i]表示祖宗节点为i的并查集内 度数为奇数的节点数量 int getf(int x) { if(x!=f[x]) { f[x]=getf(f[x]); } return f[x]; } int main() { int a,b,fa,fb,cnt; while(cin>>n>>m) { mem(f,0); mem(du,0); mem(num,0); mem(sum,0); int ans=0; for(int i=0;i<=n;i++) f[i]=i; for(int i=1;i<=m;i++) { cin>>a>>b; du[a]++; du[b]++; fa=getf(a); fb=getf(b); if(fa!=fb) f[fa]=fb; } for(int i=1;i<=n;i++) { num[getf(i)]++; if(du[i]&1) sum[getf(i)]++; } for(int i=1;i<=n;i++) { if(num[i]==0 || num[i]==1) continue; //表示节点i是孤立的 if(sum[i]>0) ans+=sum[i]/2; else if(sum[i]==0) ans++; } cout<<ans<<endl; } }