[UVA 10129] Play on Words (图的连通性 + 欧拉回路)

Play on Words

题目链接: http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=18547

题目大意:

有N个单词(均为小写) (N最大为100000),现在要将它们按照一定的规律排成一行,为能否实现?
规律是:前一个单词的最后一个字母必须是后一个单词的首字母,类似于单词接龙

解题思路:

这道题其实是一个欧拉道路问题,每个单词的首字母和尾字母相当于图中的顶点,并且有从首字母到尾字母的一条有向边。

欧拉道路:
一次这道题就是一个欧拉道路,欧拉道路满足的条件是除了起点和终点外,所有点的出度和入度相同,而起点的出度比入度大1,终点的入度比出度大1。

这道题还有个关键是要判断图是否连通,可以用并查集或者DFS搜索来实现。

并查集+欧拉道路:
//有向图欧拉回路 + 并查集判连通性
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 1000
#define INF 1<<25
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
using namespace std;
int f[30];
int find(int x)
{
    if (f[x] != x) f[x] = find(f[x]);
    return f[x];
}
int main ()
{
    int i, j, t, n;
    cin>>t;
    while(t--)
    {
        bool has[30] = {false};
        int sum = 0, a[30] = {0};
        char str[1010];
        for (i = 0; i < 26; i++) f[i] = i;
        cin>>n;
        getchar();
        while(n--)
        {
            gets(str);
            int u = str[0] - 'a', v = str[strlen(str) - 1] - 'a';
            a[u]--;
            if (!has[u])
                has[u] = true;
            a[v]++;
            if (!has[v])
                has[v] = true;
            f[find(u)] = find(v);
        }
        int no = 0, out = 0, in = 0;
        for (i = 0; i < 26; i++) if (a[i])
        {
            no++;
            if (a[i] == 1) in++;
            if (a[i] == -1) out++;
        }
        for (i = 0; i < 26; i++) if (has[i] && f[i] == i) sum++;
        if (sum == 1 && (no == 0 || (no == 2 && out == 1 && in == 1))) puts("Ordering is possible.");
        else puts("The door cannot be opened.");
    }
    return 0;
}

DFS+欧拉道路:
//有向图欧拉回路 + bfs判连通性
bfs要从有出度的点开始搜!
//有向图欧拉回路 + bfs判连通性
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 1000
#define INF 1<<25
#define mem(a, b) memset(a, b, sizeof(a))
typedef long long ll;
using namespace std;
int mp[30][30];
int bfs(int x) // 必须是对有出度的字母进行bfs!
{
    int vis[30] = {0}, font = 0, rear = 1, sum = 1;
    int que[1000] = {0};
    que[font] = x;
    vis[x] = 1;
    int u, next;
    while(font < rear)
    {
        u = que[font++];
        for (int v = 0; v < 26; v++) if (mp[u][v] && !vis[v])
        {
            vis[v] = 1;
            sum++;
            que[rear++] = v;
        }
    }
    return sum;
}
int main ()
{
    int i, j, t, n;
    cin>>t;
    while(t--)
    {
        bool has[30] = {false};
        int sum = 0, a[30] = {0}, k;
        char str[1010];
        mem(mp, 0);
        cin>>n;
        getchar();
        while(n--)
        {
            gets(str);
            int u = str[0] - 'a', v = str[strlen(str) - 1] - 'a';
            a[u]--;
            if (!has[u])
                has[u] = true, sum++;
            a[v]++;
            if (!has[v])
                has[v] = true, sum++;
            mp[u][v] = mp[v][u] = 1;
            k = u;
        }
        int no = 0, out = 0, in = 0;
        for (i = 0; i < 26; i++) if (a[i])
        {
            no++;
            if (a[i] == 1) in++;
            if (a[i] == -1) out++;
        }
        if (sum == bfs(k) && (no == 0 || (no == 2 && out == 1 && in == 1))) puts("Ordering is possible.");
        else puts("The door cannot be opened.");
    }
    return 0;
}



你可能感兴趣的:(图论,欧拉道路)