题意:
欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个图,问是否存在欧拉回路?
#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;
}
}
来源:oschina
链接:https://my.oschina.net/u/4413093/blog/3662244