UOJ #492. 单词游戏

题目描述

有 N 个盘子,每个盘子上写着一个仅由小写字母组成的英文单词。你需要给这些盘子安排一个合适的顺序,使得相邻两个盘子中,前一个盘子上单词的末字母等于后一个盘子上单词的首字母。请你编写一个程序,判断是否能达到这一要求。如果能,请给出一个合适的顺序。

输入描述

多组数据。第一行给出数据组数T,每组数据第一行给出盘子数量N,接下去N行给出小写字母字符串,一种字符串可能出现多次。

输出描述

若存在一组合法解输出“Ordering is possible.”,否则输出“The door cannot be opened.”。

样例输入

3

2

acm

ibm

3

acm

malform

mouse

2

ok

ok

样例输出

The door cannot be opened.

Ordering is possible.

The door cannot be opened.

时间限制、数据范围及描述

时间:1s 空间:64M

1<=N<=10^5;

|S|<=1000

思路:

每一个单词有用的信息只有首尾两个字母,那么建一张图令节点表示小写字母;边表示一种单词的转移。问题就变成了在图中判断欧拉路径的存在性。

若有向图G存在欧拉路径(即为半欧拉图),那么当且仅当G的基图联通且存在顶点uu的入度比出度大1,vv的入度比出度小1,其他所有顶点的入度等于出度。

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int N=1050,M=50;

int T,n,m;
char s[N];
int cnt,cnt1,cnt2;
int fa[M],u[M],v[M];

int find(int x) {
    if(fa[x]==x)
        return x;
    return fa[x]=find(fa[x]);
}

int main() {
    scanf("%d",&T);
    while (T--) {
        memset(u,0,sizeof u);
        memset(v,0,sizeof v);
        scanf("%d",&n);
        cnt=cnt1=cnt2=0;
        for(int i=1; i<=30; i++)
            fa[i]=i;
        for(int i=1; i<=n; i++) {
            scanf("%s",s+1);
            m=strlen(s+1);
            int l=s[1]-'a'+1,r=s[m]-'a'+1;
            fa[find(l)]=find(r);
            u[l]++;
            v[r]++;
        }
        for(int i=1; i<=26; i++)
            if(((u[i]||v[i])&&(find(i)==i))||abs(u[i]-v[i]) > 1)
                cnt++;
        if(cnt>1) {
            puts("The door cannot be opened.");
            continue;
        }
        for(int i=1; i<=26; i++)
            if(u[i]>v[i])
                cnt1++;
            else if(u[i]<v[i])
                cnt2++;
        if(cnt1!=cnt2||cnt1>1)
            puts("The door cannot be opened.");
        else
            puts("Ordering is possible.");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/mysh/p/11333678.html
今日推荐