Codeforces Round #375 (Div. 2) E - One-Way Reform (Fleury欧拉路径)

传送门:http://codeforces.com/contest/723/problem/E
好久没写博客了,越来越懒,也越来越菜,最近学了些新知识,准备重新调整好学习的状态。
Fleury其实就是相当于DFS,但是跟纯DFS不同,因为直接DFS的话,在某些情况下,可能会走进死路,这时候就要拿一个栈来记录路径,如果当前情况下不能扩展,就把当前这个节点输出,能扩展的话,就DFS进去,把途中的节点入栈。最后输出出来的欧拉路径其实是倒着的。

这里有一个我自己想的例子,如果直接DFS,是有可能DFS进死路,导致无法找出正确答案的。
这里写图片描述
比如这个图,如果直接1->2->3->4->1->3,就出不来了。
1->2->3->4->6->5->2->4->1->3这是一个能走完边的路径。

再讲到这题上,因为这题我是看了别人的博客的,有一个思路非常的强,就是创建一个n+1节点,把所有奇数度数节点都连到n+1上去,这样修改后的图,保证能产生欧拉回路。因为每添加一条边,图里的总度数+2,所以奇数度数的点的个数一定是偶数个,那么连了边以后,n+1那个节点的度数一定是偶数,所以每个点的度数都是偶数,因此一定会产生欧拉回路。但是因为图不一定连通,导致会产生好几个连通分量,所以要从每个点出发Fleury一次,才可以求出所有边。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <ctime>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define pb push_back
#define mp make_pair
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define calm (l+r)>>1
const int INF = 2139062143;

const int maxn=220;
int n,m;
struct EE{
    int to,next,v;
}edge[maxn*maxn];
int head[maxn],Ecnt,deg[maxn];
vector<int> st;
inline void add(int a,int b){
    edge[Ecnt].to=b;
    edge[Ecnt].next=head[a];
    edge[Ecnt].v=1;
    head[a]=Ecnt++;
}
vector<int> ans;
void dfs(int x){
    st.pb(x);
    for(int &i=head[x];~i;i=edge[i].next){
        if(!edge[i].v)continue;
        edge[i].v=edge[i^1].v=0;
        dfs(edge[i].to);
        return;
    }
}
void Fleury(int x){
    st.clear();
    ans.clear();
    st.pb(x);
    while(!st.empty()){
        bool has=false;
        int s=st.back();st.pop_back();
        for(int i=head[s];~i;i=edge[i].next){
            if(edge[i].v){
                has=true;break;
            }
        }
        if(!has){
            ans.pb(s);
        }
        else{
            dfs(s);
        }
    }
}
int main(){
    //freopen("D://input.txt","r",stdin);
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        memset(head,-1,sizeof head);
        memset(deg,0,sizeof deg);
        Ecnt=0;
        for(int i=1;i<=m;i++){
            int a,b;scanf("%d%d",&a,&b);
            add(a,b);add(b,a);
            deg[a]++;deg[b]++;
        }
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(deg[i]%2){
                cnt++;
                add(i,n+1);add(n+1,i);
            }
        }
        printf("%d\n",n-cnt);
        for(int i=1;i<=n;i++){
            Fleury(i);
            if(ans.size()>1){
                for(int j=ans.size()-1;j>=1;j--){
                    if(ans[j]!=n+1&&ans[j-1]!=n+1)printf("%d %d\n",ans[j],ans[j-1]);
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值