【JZOJ 1319】邮递员(欧拉回路)

来源:互联网 发布:手机淘宝怎样创桌面 编辑:程序博客网 时间:2024/06/06 03:05

Description

给出一张图,求一条路径,使得每个点和每条边都被访问至少一次,并输出这条路径,如有多条,则输出字典序最小的。
保证每个点被连了2,4或8次(自环算2次),有重边。

Solution

很显然,每条边都在环中,且可以有一种方案使得每个环都不相交,
有两种方法:

每走一条边,把当前边删掉,跑tarjan判断桥边,如果当前点连出的边有不是桥边的,则走不是桥边的,否则走桥边;
再加上字典序判断即可,
复杂度:O(m(n+m))

从1号点开始,先按字典序最小的不停走,直到走回点1,记录路径,
从路径最后一个开始,看看这个点还能不能继续走,如可以则继续走,把新增路径插入原来的路径

复杂度:O(n)

这里提供的是思路,这两种思路都挺好的。

Code

#include <cstdio>#include <cstdlib>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)using namespace std;const int N=205;int read(int &n){    char ch=' ';int q=0,w=1;    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());    if(ch=='-')w=-1,ch=getchar();    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;}int m,n;int B[N][N*N];int bc[N][N];int b1[N];int ans[N*N],d[N*N];bool PX(int q,int w){return q>w;}void dfs(int q){    for(int Q=q;(Q!=q||!d[0])&&B[q][0]>=0;)    {        if(bc[q][B[q][B[q][0]]])        {            d[++d[0]]=q;            bc[q][B[q][B[q][0]]]--;            bc[B[q][B[q][0]]][q]--;            B[q][0]--;            q=B[q][1+B[q][0]];        }else B[q][0]--;    }}int main(){    int q,w;    read(n),read(m);    fo(i,1,n)read(q);    fo(i,1,m)    {        read(q),read(w);        b1[q]++,b1[w]++;        B[q][++B[q][0]]=w;        B[w][++B[w][0]]=q;        bc[q][w]++,bc[w][q]++;    }    fo(i,1,n)sort(B[i]+1,B[i]+1+B[i][0],PX);    printf("%d\n",m);    if(!m)return 0;    ans[0]=ans[1]=1;    for(q=1;q>0;q--)    {        d[0]=0;        dfs(ans[q]);        if(d[0]>=1)        {            fod(i,ans[0],q)ans[i+d[0]]=ans[i];            fo(i,q,q+d[0]-1)ans[i]=d[i-q+1];            ans[0]+=d[0];            q+=d[0]+1;        }    }    fo(i,1,ans[0])printf("%d ",ans[i]);    return 0;}