define : 奇点——度数是奇数;
无向图:
1.是连通的,
2最多只有两个奇点,
则一定存在欧拉道路。
如果有两个奇点,则必须从其中一个奇点出发,另一个奇点终止;
如果无奇点,则可以从任意点出发,最终一定会回到该点(称为欧拉回路)。
有向图的结论:
1.最多两个点的入度不等于出度,
2.必须是其中一个点的出度恰好比入度大1(把它作为起点),另一个的入度比出度大1(把它作为终点)。
当然,还有一个前提条件:在忽略边的方向后,图必须是连通的。
stack<node>q;
void euler(int u){
for(int v = 0; v < n; v++) if(G[u][v] && !vis[u][v]) {
vis[u][v] = vis[v][u] = 1;
euler(v);
q.push(node(u,v));
}
}
注意:
上面是用邻接矩阵存的图。G【】【】。
但如果需要打印的是欧拉道路,在主程序
中调用时,参数必须是道路的起点。另外,打印的顺序是逆序的,因此在真正使用这份代码
时,应当把把边(u,v)压入一个栈内。
尽管上面的代码只适用于无向图,但不难改成有向图:把vis[u][v] = vis[v][u] = 1改成
vis[u][v]即可。
改成邻接表
void euler(int u)
{
for(int i = h [u] ;i ;i = e[i].nxt)
{
int v = e[i].to;
if(!e[i].vis)
{
euler(v);q.push(node(u,v));
}
}
}
例题
UVA10129 Play on Words
大意:
输入n(n≤100000)个单词,是否可以把所有这些单词排成一个序列,使得每个单词的
第一个字母和上一个单词的最后一个字母相同(例如acm、malform、mouse)。每个单词最
多包含1000个小写字母。输入中可以有重复单词
任务:判断是否有欧拉回路。分成两个小任务;
1.最多两个点的入度不等于出度.必须是其中一个点的出度恰好比入度大1(把它作为起点),另一个的入度比出度大1(把它作为终点)。
2.判断图的连通性,我用的dfs
code
bool vis[N];
//is connext ?
void dfs(int u)
{
for (int i = h[u];i;i = e[i].nxt)
{
int v = e[i].to;
if(!vis[v])
{
vis[v] = 1;
dfs(v);
}
}
}
bool checkdfs()
{
for (int i = 0;i < N ;i++)
{
if(in[i]&&!vis[i])return 0;
else if(out[i]&&!vis[i])return 0;
}
return 1;
}
//欧拉in、和out在建图的时候记录
bool ok = 1;int n1 = 0,n2 = 0;
for (int i = 0;i < N;i++)
{
if(!ok)break;
if(in[i] != out[i])
{
if(in[i] == out[i]+1)n1++;
else if(out[i] == in[i] + 1)n2++;
else {ok = 0;break;}
}
}
if(n1 && n2 && n1 + n2 > 2)ok = 0;