有向图欧拉回路 Codeforces508D Tanya and Password

欧拉回路图上瘾中,总结下用法

对于必须要用上某个单词,就取这个单词的左部分为L,右部分为R,形成一个从L到R的有向图

然后再判断是否符合欧拉回路图,即验证所有点的出度和入度,验证方法如下:


1.如果所有的点的入度都等于本身的出度,则满足欧拉回路

2.只有2个点的出度不等于入度,且一个点in比out多1,另一个点in比out少1


然后找出那个入度比出度多1的点,这个就是我们要找的起点(如果所有点的出度都等于入度,就随便取个点)

然后进行Fleury(起点)算法,算出路径,和r值

r值可以用来检测图的连通性,r的含义是访问的点的数量,所以如果整个图都是连通的,那么r必然等于n+1

否则就说明图并不只一个连通图,那么输出NO


还有个细节就是感觉递归次数多了点,,加上扩栈比较好

刚开始是用vector加vis标记边被删除的写法,但是超时了

后来发现,如果是200000个zzz,那么vector里的边并没有删除,所以还是要循环n^2次,复杂度退化到O(n^2)

然后想利用vector删除节点的方法做,开始以为vector是链表形式,在哪里删除效率都一样,所以每次循环都删除第一个,又超时了

改成每次循环先考虑最后一个,再把最后一个删除,这样做不仅删除的复杂度是O(1),而且代码比以前更简单,又一次见识到了vector并没有别人说的那么慢,反而感觉很好很强大


贴上丑陋的代码,Fleury的代码真心短,主要代码长度写在check函数上,稍微啰嗦了点

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#pragma comment(linker,"/STACK:102400000,102400000")

using namespace std;
typedef long long LL;

const int mod=1e9+7;
const int MX=250000+5;
const int INF=0x3f3f3f3f;

int Path[MX],r=0;
int IN[80000],OUT[80000];
vector<int>G[80000];

char ans[MX];

int Get(char*s){
    return s[0]*255+s[1];
}

int check(){
    int a=0,b=0,c=0,r1=-1,r2=-1;

    for(int j=0;j<=255;j++){
        for(int k=0;k<=255;k++){
            int i=j*255+k;
            if(!IN[i]&&!OUT[i]) continue;

            r1=i;
            if(IN[i]==OUT[i]) continue;

            a++;
            if(IN[i]==OUT[i]+1){
                b++;
                r2=i;
            }
            if(IN[i]+1==OUT[i]) c++;
        }
    }

    if(a==0){
        return r1;
    }else if(a==2&&b==1&&c==1){
        return r2;
    }else{
        return -1;
    }
}

void Fleury(int u){
    int s=G[u].size();
    while(s){
        int v=*(G[u].end()-1);
        G[u].erase(G[u].end()-1);

        Fleury(v);
        s=G[u].size();
    }
    Path[++r]=u;
}

int main(){
    memset(IN,0,sizeof(IN));
    memset(OUT,0,sizeof(OUT));

    int n;char word[10];

    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",word);

        int L=Get(word),R=Get(word+1);
        IN[L]++;OUT[R]++;
        G[L].push_back(R);
    }

    int Beg=check();
    if(Beg==-1){
        printf("NO\n");
        return 0;
    }

    Fleury(Beg);
    if(r!=n+1){
        printf("NO\n");
        return 0;
    }
    printf("YES\n");

    printf("%c%c",Path[r]/255,Path[r]%255);
    for(int i=r-1;i>=1;i--){
        printf("%c",Path[i]%255);
    }
    return 0;
}


你可能感兴趣的:(有向图欧拉回路 Codeforces508D Tanya and Password)