欧拉回路

无向图:
1) 设G 是连通无向图,则称经过G 的每条边一次并且仅一次的路径为欧拉通路;
2) 如果欧拉通路是回路(起点和终点是同一个顶点),则称此回路为欧拉回路(Euler circuit);
3) 具有欧拉回路的无向图G 称为欧拉图(Euler graph)。
有向图:
1) 设D 是有向图,D 的基图连通,则称经过D 的每条边一次并且仅一次的有向路径为有向欧拉通路;
2) 如果有向欧拉通路是有向回路,则称此有向回路为有向欧拉回路(directed Euler circuit);

3) 具有有向欧拉回路的有向图D 称为有向欧拉图(directed Euler graph)。


有向图D 存在欧拉通路的充要条件是:
D 为有向图,D 的基图连通,并且所有顶点的出度与入度都相等;或者除两个顶点外,其余
顶点的出度与入度都相等,而这两个顶点中一个顶点的出度与入度之差为1,另一个顶点的出度
与入度之差为-1。
推论:
1) 当D 除出、入度之差为1,-1 的两个顶点之外,其余顶点的出度与入度都相等时,D 的
有向欧拉通路必以出、入度之差为1 的顶点作为始点,以出、入度之差为-1 的顶点作为
终点。
2) 当D 的所有顶点的出、入度都相等时,D 中存在有向欧拉回路。
3) 有向图D 为有向欧拉图的充分必要条件是D 的基图为连通图,并且所有顶点的出、入度
都相等。


zoj 1395 poj 1300 DOOR MAN

管家要去把庄园里面的门关上   给定管家的起点  最后要回到0房间

且关上了的门不再打开 就是说每个门只能经过一次

两个房间之间会有门 相通

计算出房间与多少门相通就可以  就是相当于这个点的度

根据度数为奇数的进行相应的判断

如果奇数个的点数超过2或者是1个  肯定是不符合要求的

如果奇数个的点数为0  肯定是欧拉回路  但是要回到0房间 所以起点也要是0  这里就要判断

如果奇数个的点数为2  那么这两个点必须为起点和终点0  且起点不为0

数据较弱 不需要判断图的连通性

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

#define eps 1e-8
#define op operator
#define MOD  10009
#define MAXN  100100
#define INF 0x7fffffff
#define MEM(a,x)    memset(a,x,sizeof a)
#define ll __int64

using namespace std;

int mat[30];
char ch[200];

int main()
{
//freopen("ceshi.txt","r",stdin);
    while(scanf("%s",ch)&&strcmp("ENDOFINPUT",ch))
    {
        int s,n;
        scanf("%d%d",&s,&n);
        getchar();
        MEM(mat,0);
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            gets(ch);
            int len=strlen(ch);
            if(len==0)  continue;
//            cout<<"len  "<<len<<endl;
            for(int j=0;j<len;j++)
            {
                int t=0;
                while(isdigit(ch[j]))
                {
                    t=t*10+ch[j]-'0';
                    j++;
                }
//                cout<<"tt  "<<t<<endl;
                cnt++;
                mat[i]++;
                mat[t]++;
//                j--;
            }
        }
        gets(ch);
        int odd=0;
        for(int i=0;i<n;i++)
        {
            if(mat[i]%2)
                odd++;
        }
        if(odd>2||odd==1)
            puts("NO");
        else
        {
            if(odd==0)
            {
                if(s==0)
                    printf("YES %d\n",cnt);
                else  puts("NO");
            }
            else
            {
                if(mat[s]%2&&mat[0]%2&&s!=0)
                    printf("YES %d\n",cnt);
                else puts("NO");
            }
        }
    }
    return 0;
}


 zoj 2016 poj 1386 Play on Words

题目要求就是给定几个单词  将这些单词连接起来 

后一个单词的第一个字母要跟前一个单词的最后单词相同

因为单词是无法倒过来的  所以要建的是有向图

读入每个单词时,因为每个单词相当于一条从首字母指向尾字母的编码 所以单词首字母对应的顶点出度+1

尾字母对应的顶点 入度+1

需要判断图的连通性  使用并查集

有向图  判断顶点 入度与出度不想等的个数   根据有向图欧拉回路的判断条件 进行判断

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

#define eps 1e-8
#define op operator
#define MOD  10009
#define MAXN  100100
#define INF 0x7fffffff
#define MEM(a,x)    memset(a,x,sizeof a)
#define ll __int64

using namespace std;

struct edge
{
    int u,v;
};
edge e[MAXN];//每个单词建一条边

char word[1010];
int n;
int rd[30],cd[30];//入度 出度
int vis[30];//记录该字母有木有出现
int parent[30];

void init()
{
    for(int i=0;i<26;i++)
        parent[i]=-1;
}

int Find(int x)
{
    int s;
    for(s=x;parent[s]>=0;s=parent[s]);
    while(s!=x)//压缩路径
    {
        int tmp=parent[x];
        parent[x]=s;
        x=tmp;
    }
    return s;
}

void Union(int R1,int R2)
{
    int r1=Find(R1); int r2=Find(R2);
    int tmp=parent[r1]+parent[r2];
    if(parent[r1]>parent[r2])
    {
        parent[r1]=r2;
        parent[r2]=tmp;
    }
    else
    {
        parent[r2]=r1;
        parent[r1]=tmp;
    }
}

bool is_connected()
{
    init();
    for(int i=0;i<n;i++)
    {
        int u=e[i].u; int v=e[i].v;
        if(u!=v&&Find(u)!=Find(v))
            Union(u,v);
    }
    int fir=-1;
    for(int j=0;j<26;j++)
    {
        if(vis[j]==0)  continue;
        if(fir==-1)  fir=j;
        else
        {
            if(Find(fir)!=Find(j))
            {
//                cout<<"fir  "<<fir<<"  "<<Find(fir)<<"   jj "<<j<<"  "<<Find(j)<<endl;
                return 0;
            }
        }
    }
    return 1;
}

int main()
{
//freopen("ceshi.txt","r",stdin);
    int tc;
    scanf("%d",&tc);
    while(tc--)
    {
        scanf("%d",&n);
        getchar();
        MEM(rd,0); MEM(cd,0); MEM(vis,0);
        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';
//            cout<<"uu "<<u<<"  vv"<<v<<endl;
            e[i].u=u; e[i].v=v;
            vis[u]=1; vis[v]=1;
            cd[u]++;  rd[v]++;
        }
        int flag=1;//记录是否符合欧拉图的条件
        int rc=0,cr=0; //入度-出度=1的个数  出度-入度=1的个数
        for(int i=0;i<26;i++)
        {
            if(vis[i]==0)  continue;
            if(rd[i]-cd[i]>=2||cd[i]-rd[i]>=2)
            {
                flag=0; break;
//                cout<<"1111"<<endl;
            }
            if(rd[i]-cd[i]==1)
            {
                rc++;
                if(rc>1)
                {
                    flag=0; break;
//                    cout<<"2222"<<endl;
                }
            }
            if(cd[i]-rd[i]==1)
            {
                cr++;
                if(cr>1)
                {
                    flag=0; break;
//                    cout<<"3333"<<endl;
                }
            }
        }
        if(rc!=cr)//其中有一个为0  一个为1
        {
            flag=0;
//            cout<<"4444"<<endl;
        }
        if(!is_connected())
        {
            flag=0;
//            cout<<"5555"<<endl;
        }
        if(flag==0)
            printf("The door cannot be opened.\n");
        else printf("Ordering is possible.\n");
    }
    return 0;
}


poj 2513 Coloured Sticks

给定棍子两端的颜色  将这些棍子连在一起  使得相邻两根棍子的连接处端点的颜色一样

这题总的来说跟上题是差不多的   但是由于棍子头尾是可以交换的  所以建无向图

但是由于顶点是字符串  所以一开始想到的是用map来存储  

发现不行  用trie树来进行存储  

还要进行改变的是 并查集的写法  如果用上题的写法的话 parent数组当中的值可能会超int

trie树insert操作返回该字符串的序号 根据这个 序号来建图 

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

#define eps 1e-8
#define op operator
#define MOD  10009
#define MAXN  600100
#define INF 0x7fffffff
#define MEM(a,x)    memset(a,x,sizeof a)
#define ll __int64

using namespace std;

struct trie_node
{
    int id;
    int next[26];
    trie_node()
    {
        for(int i=0;i<26;i++)
            next[i]=0;
        id=-1;
    }
};
trie_node node[810000];
int parent[MAXN],deg[MAXN];
int num;
int trienum=2;//树中节点个数

void init()
{
    for(int i=0;i<MAXN;i++)
        parent[i]=i;
    MEM(deg,0);
    num=0;
}

int Find(int x)
{
    return x==parent[x]?x:parent[x]=Find(parent[x]);
}

void Union(int R1,int R2)
{
    int r1=Find(R1),r2=Find(R2);
    if(r1==r2)  return;
    parent[r1]=r2;
}

int trie_insert(char *word)
{
    int ptr=1;
    char *p=word;
    while(*p)
    {
        int now=*p-'a';
        if(!node[ptr].next[now])
            node[ptr].next[now]=trienum++;
//        cout<<trienum<<endl;
        ptr=node[ptr].next[now];
        p++;
    }
    if(node[ptr].id==-1)
    {
        node[ptr].id=num++;
    }
    return node[ptr].id;
}

bool is_connected()
{
    int cnt=0;
    for(int i=0;i<num;i++)
        if(parent[i]==i)
            cnt++;
    return cnt==1;
}

bool Euler()
{
    int cnt=0;
    for(int i=0;i<num;i++)
        if(deg[i]&1)
            cnt++;
    if(cnt==0||cnt==2)
        return 1;
    return 0;
}

int main()
{
//freopen("ceshi.txt","r",stdin);
    init();
    char s1[15],s2[15];
    while(scanf("%s%*c%s%*c",s1,s2)!=EOF)
    {
        int u=trie_insert(s1);
        int v=trie_insert(s2);
        Union(u,v);
        deg[u]++; deg[v]++;
    }
    if(num==0)  puts("Possible");
    else
    {
        if(is_connected()&&Euler())
            puts("Possible");
        else puts("Impossible");
    }
    return 0;
}


//根据要求选择 有向图 无向图建图  要注意判断图的连通性

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值