算法总结之欧拉回路
来源:互联网 发布:家装平面图软件 编辑:程序博客网 时间:2024/04/27 14:42
欧拉回路的作用:
在一张有向或无向图中求出一笔画问题的具体画法。
模板题:http://uoj.ac/problem/117
算法:
首先我们考虑如何判定这个图是否为欧拉回路
这时候我们对于有向图和无向图有不同的判定方法。
对于有向图,保证每个点的入度等于出度。
对于无向图,保证每个点的度数为偶数。
通常我们判断图是否联通,是在求欧拉回路(见下文)的过程中记录用到的边的数量,看是否与给定的边相等,若相等则联通。
因为如果通过深搜判断点的数量,可能题意描述点有n个,实际上一些点为单点,欧拉回路求的是道路,单点不影响。会出现误判。
然后我满考虑如何求出确切的欧拉回路。
我们可以用一个dfs来解决问题。
void yxdfs(int x,int beg)
{
int ytp = head[x];
head[x] = nxt[ytp];
outd[x]--;
ind[to[ytp]]--;
jlb++;
if
(to[ytp] != beg)
yxdfs(to[ytp],beg);
dl.push_back(ytp);
if
(head[x])
yxdfs(x,x);
}
参数x,表示当前搜到的点,beg表示这次搜索的起点。
我们删掉当前点的第一条边,如果删掉的这条边的指向不为搜索起点,那我们就不改变起点继续想下搜。并且搜回来记录我走的是那条边。如果说发现这条边还可以走出其他边,显然我们可以理解为从已经搜出的一张一笔画上,再从这点出发,再添加上一个一笔画,就像我们开始搜出了一条直线,后来在回溯的过程中,我们发现,有一个还有多余的边,那么从这点继续进行一笔画,并将其加入答案数组中,构成完整的一笔画。
同理无向图的dfs,删边稍微麻烦了一些,需要删除反向边,其余都一样。
最后我们获得了一个答案数组,我们应该如何将这个数组输出。
我们先考虑有向图,我们最早搜的点,是最后放入答案数组的,如果我们反向输出答案数组,那么显然边的指向是反的。所以我们要正想输出答案数组。
我们再考虑无向图。显然无论正反输出,对于边没有影响,虽然如此,我们的输出仍应该与样例保持一致,增加程序鲁棒性。
AC代码:
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
int n,m,t,tp1,tp2,sum,js,jlb;
int head[200000],nxt[500000],to[500000],ind[200000];
int tod[200000],fx[500000],outd[200000];
bool vis[20000];
vector <int> dl;
void cr(int x,int y)
{
sum++;
nxt[sum] = head[x];
head[x] = sum;
to[sum] = y;
}
bool pd1()
{
for
(int i = 1; i <= n; i++)
{
if
(ind[i] & 1)
return
false
;
}
return
true
;
}
void del(int x,int y)
{
if
(to[head[x]] == y)
{
head[x] = nxt[head[x]];
return
;
}
for
(int i = head[x]; i; i = nxt[i])
{
if
(to[nxt[i]] == y)
{
nxt[i] = nxt[nxt[i]];
return
;
}
}
}
void wxdfs(int x,int beg)
{
int wtp = head[x];
head[x] = nxt[wtp];
del(to[wtp],x);
ind[x]--;
jlb++;
ind[to[wtp]]--;
if
(to[wtp] != beg && to[wtp])
wxdfs(to[wtp],beg);
if
(wtp) dl.push_back(wtp);
if
(head[x]) wxdfs(x,x);
}
void work1()
{
for
(int i = 1; i <= n; i++)
{
if
(ind[i])
{
wxdfs(i,i);
break
;
}
}
}
void print1()
{
for
(int i = 0; i < dl.size(); i++)
{
int tan = 0;
tan = (dl[i] + 1) / 2;
if
(dl[i] & 1) tan *= -1;
printf(
"%d "
,tan);
}
}
void read1()
{
scanf(
"%d%d"
,&n,&m);
for
(int i = 1; i <= m; i++)
{
scanf(
"%d%d"
,&tp1,&tp2);
cr(tp1,tp2);
cr(tp2,tp1);
ind[tp1]++;
ind[tp2]++;
}
if
(!pd1())
{
printf(
"NO\n"
);
return
;
}
else
{
work1();
if
(jlb < m) printf(
"NO\n"
);
else
{
printf(
"YES\n"
);
print1();
}
}
}
bool pd2()
{
for
(int i = 1;i <= n;i++)
{
if
(ind[i] != outd[i])
return
false
;
}
return
true
;
}
void print2()
{
for
(int i = dl.size() - 1;i >= 0;i--)
printf(
"%d "
,dl[i]);
}
void yxdfs(int x,int beg)
{
int ytp = head[x];
head[x] = nxt[ytp];
outd[x]--;
ind[to[ytp]]--;
jlb++;
if
(to[ytp] != beg)
yxdfs(to[ytp],beg);
dl.push_back(ytp);
if
(head[x])
yxdfs(x,x);
}
void work2()
{
for
(int i = 1;i <= n;i++)
{
if
(outd[i])
{
yxdfs(i,i);
break
;
}
}
}
void read2()
{
scanf(
"%d%d"
,&n,&m);
for
(int i = 1;i <= m;i++)
{
scanf(
"%d%d"
,&tp1,&tp2);
cr(tp1,tp2);
ind[tp2]++;
outd[tp1]++;
}
if
(!pd2())
{
printf(
"NO\n"
);
}
else
{
work2();
if
(jlb < m)
{
printf(
"NO\n"
);
return
;
}
else
{
printf(
"YES\n"
);
print2();
}
}
}
void sread()
{
scanf(
"%d"
,&t);
if
(t == 1) read1();
else
read2();
}
int main()
{
sread();
return
0;
}
- 算法总结之欧拉回路
- ACM算法之 欧拉回路
- 算法学习之欧拉回路
- 欧拉回路算法
- 欧拉回路总结
- 欧拉回路总结
- 算法之----欧拉回路,欧拉通路,半欧拉图
- 欧拉回路算法实现
- 欧拉回路Fleury算法
- 欧拉回路算法学习
- 欧拉回路的总结
- 欧拉回路学习总结
- 欧拉回路/路径【总结】
- hdu1878之欧拉回路
- 欧拉图,欧拉回路,以及求欧拉回路的Fleury算法
- 欧拉回路算法C语言
- 求解欧拉回路的算法
- fleury算法输出欧拉回路
- 作业1634045
- 勾股定理一日一证连载119
- 关于MYSQL的基本命令
- 关于Eclipse开发安卓系统时的继承问题
- Coderforces 374 (Div2)
- 算法总结之欧拉回路
- HTTP协议总结
- 我在学习Java时遇到的一些问题
- UVa 10570 Meeting with Aliens(思路)
- 视觉SLAM漫谈(一)
- 视觉SLAM漫谈(二):图优化理论与g2o的使用
- 视觉SLAM漫谈 (三): 研究点介绍
- java基础50题(5)
- plugins有很多选项都变成灰色不可用