并查集求欧拉回路/通路

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1116


题意:给你一些英文单词,判断所有单词能不能连成一串,类似成语接龙。但是如果有多个重复的单词时,也必须满足这样的条件才能算YES。否则都是不可能的情况。


分析:我们以每个单词的首尾为节点建立有向图,然后再判断这个图是否是欧拉通路或者是欧拉回路就行了。当然用并查集判断。



那么先了解概念:


欧拉通路:除首尾结点外,其余结点入度等于出度,起点出度减入度等于1,终点入度减出度等于1。

欧拉回路:所有结点的入度都等于出度。


#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
const int N = 26;

int pre[N];
int IN[N],OT[N],p[N];
bool vis[N];
char str[1005];

void Init()
{
    memset(vis,0,sizeof(vis));
    memset(IN,0,sizeof(IN));
    memset(OT,0,sizeof(OT));
    for(int i=0;i<N;i++)
        pre[i] = i;
}

int Find(int x)
{
    if(pre[x] != x)
        pre[x] = Find(pre[x]);
    return pre[x];
}

void Union(int x,int y)
{
    x = Find(x);
    y = Find(y);
    if(x == y) return;
    pre[x] = y;
}

int main()
{
    int T,n;
    scanf("%d",&T);
    while(T--)
    {
        Init();
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",str);
            int len = strlen(str);
            int x = str[0] - 'a';
            int y = str[len-1] - 'a';
            Union(x,y);
            OT[x]++;
            IN[y]++;
            vis[x] = vis[y] = 1;
        }
        int cnt = 0;
        for(int i=0;i<N;i++)
        {
            pre[i] = Find(i);
            if(vis[i] && pre[i]==i)
                cnt++;
        }
        if(cnt > 1)
        {
            puts("The door cannot be opened.");
            continue;
        }
        int k = 0;
        for(int i=0;i<N;i++)
        {
            if(vis[i] && IN[i] != OT[i])
                p[k++] = i;
        }
        if(k == 0)
        {
            puts("Ordering is possible.");
            continue;
        }
        if(k == 2 && ((OT[p[0]] - IN[p[0]] == 1 && IN[p[1]] - OT[p[1]] == 1) || (OT[p[1]] - IN[p[1]] == 1 && IN[p[0]] - OT[p[0]] == 1)))
        {
            puts("Ordering is possible.");
            continue;
        }
        puts("The door cannot be opened.");
    }
    return 0;
}



你可能感兴趣的:(并查集求欧拉回路/通路)