zoukankan      html  css  js  c++  java
  • 欧拉回路总结

    1.基本概念:

    图G为连通图,若图G中存在一条路径经过每条边一次且仅一次,那么这条路径为欧拉路,若这条路径的起点与终点相同,那么为欧拉回路。欧拉回路是欧拉路的特例。

    存在欧拉回路的图称为欧拉图。欧拉路以及欧拉回路常用于解决一笔画问题。

    2.判定条件。

    无向图:

      1).欧拉路:

        ①图连通,可用并查集判定;

        ②度数为奇数的结点为2个。(一个作起点,一个作终点)

      2)欧拉回路:

        ①图连通

        ②度数为奇数的结点为0个

    有向图:

      1)欧拉路:

       ①图连通。从某点开始能将所有访问 dfs+vis[],见POJ2337

       ②起点的出度比入度大1,终点的入度比出度大1,其他结点的出度=入度

      2)欧拉回路

       ②图连通

       ②所有结点的出度=入度

    3.题目练习:

    poj2337

    思路:向前星先加入的边后访问

    #include <iostream>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <vector>
    #include <set>
    using namespace std;
    const int MAXN=1005;
    struct Edge{
        int to;
        int next;
        int index;
        bool mark;
    }es[MAXN];
    int head[MAXN];
    int tot;
    void addedge(int u,int v,int index)
    {
        es[tot].to=v;
        es[tot].next=head[u];
        es[tot].mark=false;
        es[tot].index=index;
        head[u]=tot++;
    }
    set<int> node;
    int n;
    vector<string> vec;
    int indeg[30];
    int outdeg[30];
    int ans[MAXN];
    int cnt;
    void dfs(int u)
    {
        for(int i=head[u];i!=-1;i=es[i].next)
        {
            if(!es[i].mark)
            {
                es[i].mark=true;
                dfs(es[i].to);
                ans[cnt++]=es[i].index;
            }
        }
    }
    int main()
    {
        int T;
        cin>>T;
        while(T--)
        {
            node.clear();
            vec.clear();
            tot=0;
            cnt=0;
            memset(head,-1,sizeof(head));
            memset(indeg,0,sizeof(indeg));
            memset(outdeg,0,sizeof(outdeg));
            cin>>n;
            for(int i=0;i<n;i++)
            {
                string s;
                cin>>s;
                vec.push_back(s);
            }
            sort(vec.begin(),vec.end());
            int start=100;
            for(int i=vec.size()-1;i>=0;i--)
            {
                string s=vec[i];
                int u=s[0]-'a';
                int v=s[s.length()-1]-'a';
                addedge(u,v,i);
                node.insert(u);
                node.insert(v);
                outdeg[u]++;
                indeg[v]++;
                start=min(start,u);    
            }
            int c1=0,c2=0,c3=0;
            for(int i=0;i<30;i++)
            {
                if(indeg[i]==0&&outdeg[i]==0)
                    continue;
                if(indeg[i]==outdeg[i])
                    c1++;
                else if(outdeg[i]-indeg[i]==1)
                {
                    c2++;
                    start=i;
                }
                else if(indeg[i]-outdeg[i]==1)
                    c3++;
            }
            if(!(c1==node.size()-2&&c2==1&&c3==1)&&!(c1==node.size()&&c2==0&&c3==0))
            {
                cout<<"***"<<endl;
                continue;
            }
            dfs(start);
            if(cnt!=n)
            {
                cout<<"***"<<endl;
                continue;
            }
            for(int i=cnt-1;i>=0;i--)
            {
                cout<<vec[ans[i]];
                if(i>0)
                    cout<<".";
            }
            cout<<endl;
        }
        return 0;
    }

     HDU3018

    思路:求一幅图是几笔画的,答案是度为奇数的结点个数/2,注意孤立点不算,且图不连通。

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    using namespace std;
    const int MAXN=100005;
    int deg[MAXN];
    int par[MAXN];
    int n,m;
    set<int> roots;
    vector<int> nodes[MAXN];
    void prep()
    {
        for(int i=0;i<MAXN;i++)
        {
            par[i]=i;
        }
    }
    int fnd(int x)
    {
        if(x==par[x])
            return x;
        return par[x]=fnd(par[x]);
    }
    void unite(int x,int y)
    {
        int a=fnd(x);
        int b=fnd(y);
        par[a]=b;
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            for(int i=0;i<MAXN;i++)
                nodes[i].clear();
            roots.clear();
            prep();
            memset(deg,0,sizeof(deg));
            for(int i=0;i<m;i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                deg[u]++;
                deg[v]++;
                unite(u,v);
            }
            for(int i=1;i<=n;i++)
            {
                int root=fnd(i);
                nodes[root].push_back(i);
                roots.insert(root);
            }
            int res=0;
            for(set<int>::iterator it=roots.begin();it!=roots.end();it++)
            {
                if(nodes[*it].size()==1)//孤立点不算 
                    continue;
                int s=0;
                for(int i=0;i<nodes[*it].size();i++)
                {
                    int u=nodes[*it][i];
                    if(deg[u]%2==1)
                        s++;
                }
                if(s==0)
                    res+=1;
                else res+=(s/2);
            }
            printf("%d
    ",res);
        }
        return 0;
    }

     POJ1386

    思路:一笔画问题,并查集判连通

    #include <cstdio>
    #include <cstring>
    using namespace std;
    int indeg[30];
    int outdeg[30];
    int vis[30];
    int par[30];
    void prep()
    {
        for(int i=0;i<30;i++)
        {
            par[i]=i;
        }
    }
    
    int fnd(int x)
    {
        if(x==par[x])
            return x;
        return par[x]=fnd(par[x]);
    }
    
    void unite(int x,int y)
    {
        int a=fnd(x);
        int b=fnd(y);
        par[a]=b;
    }
    int main()
    {
        int T;
        scanf("%d",&T);
        while(T--)
        {
            memset(indeg,0,sizeof(indeg));
            memset(outdeg,0,sizeof(outdeg));
            memset(vis,0,sizeof(vis));
            prep();
            int n;
            scanf("%d",&n);
            int nodes=0;
            char word[1005]="";
            for(int i=0;i<n;i++)
            {
                scanf("%s",word);
                int len=strlen(word);
                int u=word[0]-'a';
                int v=word[len-1]-'a';
                unite(u,v);    
                if(!vis[u])
                {
                    vis[u]=1;
                    nodes++;
                }
                if(!vis[v])
                {
                    vis[v]=1;
                    nodes++;
                }
                outdeg[u]++;
                indeg[v]++;
            }
            int c1=0,c2=0,c3=0;
            for(int i=0;i<30;i++)
            {
                if(indeg[i]==0&&outdeg[i]==0)
                    continue;
                if(outdeg[i]-indeg[i]==1)
                {
                    c1++;
                }
                else if(outdeg[i]==indeg[i])
                {
                    c2++;
                }
                else if(indeg[i]-outdeg[i]==1)
                {
                    c3++;
                }
            }
            if(!(c1==1&&c2==nodes-2&&c3==1)&&!(c1==0&&c2==nodes&&c3==0))
            {
                printf("The door cannot be opened.
    ");
                continue;
            }
            int cnt=0;
            int root=-1;
            for(int i=0;i<30;i++)
            {
                if(vis[i])
                {
                    int f=fnd(i);
                    if(f!=root)
                    {
                        root=f;
                        cnt++;
                    }
                }
            }
            if(cnt!=1)
            {
                printf("The door cannot be opened.
    ");
            }
            else
            {
                printf("Ordering is possible.
    ");
            }
        }
        return 0;
    }

     POJ2513

    思路:字典树+无向图一笔画问题

    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int MAXN=510005;
    struct Trie{
        int val;
        Trie *next[26];
    };
    Trie memory[MAXN];
    Trie *root;
    int tot;
    int deg[MAXN];
    Trie* Create()
    {
        Trie *p=&memory[tot++];
        for(int i=0;i<26;i++)
            p->next[i]=NULL;
        return p;
    }
    
    void Insert(char buf[],int x)
    {
        int len=strlen(buf);
        Trie *p=root;
        for(int i=0;i<len;i++)
        {
            int k=buf[i]-'a';
            if(p->next[k]==NULL)
            {
                p->next[k]=Create();
            }
            p=p->next[k];
        }
        p->val=x;
    }
    
    int Search(char buf[])
    {
        int len=strlen(buf);
        Trie *p=root;
        for(int i=0;i<len;i++)
        {
            int k=buf[i]-'a';
            if(p->next[k]==NULL)
            {
                return -1;
            }
            p=p->next[k];
        }
        return p->val;
    }
    
    int par[MAXN];
    
    void prep()
    {
        for(int i=0;i<=MAXN;i++)
        {
            par[i]=i;
        }
    }
    
    int fnd(int x)
    {
        if(x==par[x])
            return x;
        return par[x]=fnd(par[x]);
    }
    
    void unite(int x,int y)
    {
        int a=fnd(x);
        int b=fnd(y);
        par[a]=b;
    }
    
    int main()
    {
        root=Create();
        int cnt=0;
        char first[15]="";
        char last[15]="";
        prep();
        while(scanf("%s%s",first,last)!=EOF)
        {
            int x=Search(first);
            int y=Search(last);
            if(x==-1)
            {
                x=cnt;
                Insert(first,x);
                cnt++;
            }
            if(y==-1)
            {
                y=cnt;
                Insert(last,y);
                cnt++;
            }
            deg[x]++;
            deg[y]++;
            unite(x,y);
        }
        int odds=0;
        int rt=-1,roots=0;
        for(int i=0;i<cnt;i++)
        {
            int f=fnd(i);
            if(f!=rt)
            {
                rt=f;
                roots++;
            }
            if(deg[i]%2==1)
                odds++;
        }
        if(roots<=1&&(odds==0||odds==2))
        {
            printf("Possible
    ");
        }
        else
        {
            printf("Impossible
    ");
        }
        
        return 0;
    }
  • 相关阅读:
    Postfix常用命令和邮件队列管理(queue)
    window7下面rabbitMQ安装配置过程详解
    RabbitMQ系列之消息确认机制
    全文检索:sphinx elasticsearch xunsearch 比较
    用SQL命令查看Mysql数据库大小
    部署Percona监控和管理--- PMM Server
    什么是MTU?为什么MTU值普遍都是1500?
    Mysql删除数据后,磁盘空间未释放的解决办法
    数据库索引
    visual studio 容器工具首次加载太慢 vsdbgvs2017u5 exists, deleting 的解决方案
  • 原文地址:https://www.cnblogs.com/program-ccc/p/5432773.html
Copyright © 2011-2022 走看看