序言:
首先感谢@G20222222_tly学长提供的关于dfs的思路一份。
在此之前,如果看过我之前写的博客的同学,不必担心,只需要,忘记!
引子:
额,这道题,以平常的题目,过人的惊天数据来展示什么叫毒瘤。
然后去看了一下题解, 自己又重码了一遍,结果重新再来看的时候是一脸懵逼嗄。
然后想了将近一晚上的思路终于有了起色。
下面就是我的一些见解,和代码
代码及其思路
首先加入快读,是因为原代码是刚好卡着时间过的,
如果要按照,本人目前所学的东西来写的话
直接超时,不用说了。
关于dfs最新的思路就是这样的:
就是退回来的时候的边塞进ans里面,意思就是:
我们首先考虑就是无向边会拆分成正反两条边,
第 j j j条边,正向就是 > > 1 >> 1 >>1,反向就是 j < < 1 ∣ 1 j << 1 | 1 j<<1∣1
若要在正反两条边上同时打一个 v i s vis vis标记,就打在 j > > 1 j >> 1 j>>1上。
~~ 以上来自tly学长思路 ~~
之后就是判断是否是有向图或无向图, 如果都不是那就没有欧拉回路,而且如果图不连通也是不存在的
最后就是将思路里讲的处理负数
/*
当图是无向图时,欧拉回路的存在条件为所有点的入度为偶数
当图是有向图时,欧拉回路的存在条件是所有点的入度等于出度
求欧拉回路时dfs所有边 如果这条边当前没被标记过
那就标记这条边,并且继续向下深搜,把经过的边存进数组里
同时要求实现有向图和无向图,无向图就是多建了一些边
回溯时存下所有边
然后在返回输出的时候处理负数
并且倒叙输出
*/
#include<cstdio>
#define maxn 100005
#define maxm 200005
using namespace std;
int last[maxn];//储存链式前向星
int ecnt = 1 ;//边数
int cnt; //奇度顶点个数的计数器
int ans[maxm];//储存欧拉回路
int in_deg[maxn], out_deg[maxn];//入度 ,出度
bool vis[maxm];//记录有无关联边
int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x * f;
}
struct node{
int next, to;
}e[maxm << 1];
void add(int a, int b){
//点与点之间有无关联
e[++ecnt] = (node){
last[a], b};
last[a] = ecnt;
}
void dfs(int x){
for(int &i = last[x]; i; i = e[i].next){
int y = e[i].to, j = i;
if(!vis[j >> 1]){
vis[j >> 1] = 1;
dfs(y);
ans[++cnt] = j;
}
}
}
int main(){
int t, n, m, a, b;
t = read();
n = read();
m = read();
for(int i = 1; i <= m; i++){
a = read();
b = read();
add(a , b);
if(t == 1)add(b , a), in_deg[a]++, in_deg[b]++;//无向图 出入度加一
else ecnt++, in_deg[b]++, out_deg[a]++;
}
if(t == 1){
//有一条无向边
for(int i = 1; i <= n; i++)
if((in_deg[i] + out_deg[i]) & 1){
//如果某点的度是奇数
printf("NO\n");
return 0;
}
}
else {
//有一条有向边
for(int i = 1; i <= n; i++)
if(in_deg[i] != out_deg[i]){
printf("NO\n");
return 0;
}
}
dfs(a);
if(cnt != m){
//如果图并不是联通的
puts("NO");
}
else{
//相反操作
puts("YES");
for(int i = cnt; i; i--){
printf("%d ",ans[i]&1?-(ans[i]>>1):(ans[i]>>1));
}
}
}
这个注释和思路,大概率会有错,如有问题,请指出!