[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\n%d\n",ans-1,res[1].second);
    for(int i=2;i<=cnt;i++)
        printf("%d %d\n",res[i].first,res[i].second);
    return 0;
}

 

posted @ 2019-08-23 17:42  Rorschach_XR  阅读(141)  评论(0编辑  收藏  举报
//雪花飘落效果