写一道题解证明自己不仅仅学了概念,顺便庆祝一下第一次用链式前向星,原因是链接表不知道怎么优化
题目描述
原题来自:UOJ #117
有一天一位灵魂画师画了一张图,现在要你找出欧拉回路,即在图中找一个环使得每条边都在环上出现恰好一次。
一共两个子任务:
1.这张图是无向图。(50 分)
2.这张图是有向图。(50 分)
样例
样例输入 1
复制1
3 3
1 2
2 3
1 3
样例输出 1
复制YES
1 2 -3
样例输入 2
复制2
5 6
2 3
2 5
3 4
1 2
4 2
5 1
样例输出 2
复制YES
4 1 3 5 2 6
我解释起来很心累,大家还是康康代码的注释吧,这道题目剪枝除了剪枝有一点点难想,其他都还好:
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std ;
const int MAXN = 4e5 + 5 ;
bool Vis[MAXN] ;
int n, m, t, a, b, cnt = 0, Num = 0, tot = 0 ;
int u[MAXN], v[MAXN], D[MAXN], ans[MAXN], head[MAXN] ;
struct Edge
{
int to, next, w ;
}G[MAXN] ;
void add(int u, int v, int w)
{
cnt ++ ;
G[cnt].to = v ;
G[cnt].w = w ;
G[cnt].next = head[u] ;
head[u] = cnt ;
}
void Dfs(int now)
{
for(int i = head[now]; i; i = head[now])
{
int w = G[i].w ;
if(Vis[abs(w)] == 1)
{
head[now] = G[i].next ; //下一次直接循环next边,且自动删除这条边,剪枝
continue ;
}
Vis[abs(w)] = 1 ;
head[now] = G[i].next ;//删除这条边,剪枝
Dfs(G[i].to) ;
ans[++tot] = w ;//存储答案,后面倒着输出
}
}
int main()
{
scanf("%d", &t) ;
if (t == 1)//无向图的情况
{
scanf("%d%d", &n, &m) ;
for (int i = 1; i <= m; i ++)
{
scanf("%d%d", &a, &b) ;
if(i == 1) Num = a ;
D[a] ++, D[b] ++ ;//欧拉回路基本判定方法,可以去翻翻我的关于欧拉回路的判定方法
add(a, b, i) ;
add(b, a, -i) ;//题目要求,反着输出-i
}
for (int i = 1; i <= n; i ++)
{
if(D[i] % 2 == 1)
{
printf("NO\n") ;
return 0 ;
}
}
}
else
{
scanf("%d%d", &n, &m) ;
for (int i = 1; i <= m; i ++)
{
scanf("%d%d", &a, &b) ;
if(i == 1) Num = a ;
u[b] ++, v[a] ++ ;
add(a, b, i) ;
}
for (int i = 1; i <= n; i ++)
{
if(u[i] != v[i])
{
printf("NO\n") ;
return 0 ;
}
}
}
Dfs(Num) ;
if (tot < m)
{
printf("NO") ;
return 0 ;
}
printf("YES\n") ;
for (int i = tot; i >= 1; i --) printf("%d ", ans[i]) ;
}