• [jzoj5840]Miner 题解(欧拉路)


    首先考虑第一问。每个联通块的情况是相对独立的,所以可以分别求每个联通块的答案。无向图中存在欧拉路的条件是奇点数为0或2,那么合法方案肯定是tp到一个奇点,通过一条欧拉路到另一个奇点,再tp到另一个奇点……

    设共k个联通块,第$i$个里奇点个数为$c_i$,那么答案即为$sum_{i=1}^k max(1,frac c2)-1$,最后-1是因为选起点不用浪费传送次数。

    关于构造方案,我们先对于每个联通块求它内部的奇点。如果没有的话直接跑欧拉路即可。

    如果有奇点,那么必有偶数个,因为每个联通块的点的度数之和必为偶数。可以新建一个源点,向所有奇点连边,再跑欧拉路。

    最后的方案输出:

    如果从源点到某个点,那这个点一定是奇点,操作为1 x。

    从某个点跑到源点,显然不用管。

    从点x跑到点y,操作为0 y。

    另外,写暴力圈套圈的欧拉路算法还是要用非递归版的,直接dfs有可能爆栈也可能直接T掉(递归很慢)。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define pa pair<int,int>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int N=1e5+5;
    int n,m;
    int to[N*10],nxt[N*10],head[N],tot=1,deg[N];
    int st[N*10],top,vis[N],v[N*10];
    int ans=0,cnt;
    pa res[N*10];
    void add(int x,int y)
    {
        to[++tot]=y;
        nxt[tot]=head[x];
        head[x]=tot;
        deg[x]++;
    }
    void dfs(int x)
    {
        vis[x]=1;
        if(deg[x]&1)st[++top]=x;
        for(int i=head[x];i;i=nxt[i])
            if(!vis[to[i]])dfs(to[i]);
        return ;
    }
    int syst[N*10],systop;
    void euler()
    {
        systop=0;
        syst[++systop]=0;
        while(systop>0)
        {
            int x=syst[systop],i=head[x];
            while(i&&v[i])i=nxt[i];
            if(i)
            {
                syst[++systop]=to[i];
                v[i]=v[i^1]=1;
                head[x]=nxt[i];
            }
            else systop--,st[++top]=x;
        }
    }
    
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int x=read(),y=read();
            add(x,y);add(y,x);
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            if(deg[i]&&!vis[i])
            {
                top=0;
                dfs(i);
                head[0]=0;
                if(!top)add(0,i),add(i,0),add(i,0),add(0,i);
                else while(top){int now=st[top--];add(0,now);add(now,0);};
                euler();
                int now;
                while(top>1)
                {
                    now=st[top--];
                    if(now)
                        res[++cnt]=make_pair(0,now);
                    else res[++cnt]=make_pair(1,st[top--]),ans++;
                }
            }
        }
        printf("%d
    %d
    ",ans-1,res[1].second);
        for(int i=2;i<=cnt;i++)
            printf("%d %d
    ",res[i].first,res[i].second);
        return 0;
    }
    
  • 相关阅读:
    从一个小程序跳到另一个小程序的写法
    小程序input组件失焦的使用
    小程序弹框wx.showModal的使用
    小程序在选择某一个东西的时候,可以用if,else 来做
    reverse啥时候可以用
    js中array.some()的用法
    element ui的table的头部自定义
    逻辑表达式
    cookie
    命名
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11401631.html
Copyright © 2020-2023  润新知