hdu 1116

题目概述:

有一扇密码门,上面有N个字符串

每个字符串s,如果经排序后可使所有字符串首尾相接(前一个末字符和后一个首字符同),则门会打开

输入:

第一行times,下一行N,其后N行,每行s

输入有times组

限制:

1<=N<=1e5;2<=s长度<=1000;s只含小写字母;同一组数据中可能有重复的s

输出:

一个字符串,若门有可能打开,则输出

Ordering is possible.

否则输出:

The door cannot be opened.

多组输出之间没有空行

样例输入:

6
2
acm
ibm
3
acm
malform
mouse
2
ok
ok
3
yes
yes
sey
1
yes
4
no
no
no
on

样例输出:

The door cannot be opened.
Ordering is possible.
The door cannot be opened.
Ordering is possible.
Ordering is possible.
The door cannot be opened.

讨论:

一个字符串最长1000,然而仅用到首尾那两个,构成一条有向路,因此这个题虽然有十万个字符串,但是数组都近开到26,因为小写字母只有26个,也是怕混淆,没有用MAXN常量,把字母看做节点,这个题就是判断欧拉路和欧拉回路的存在性

题解状态:

280MS,1728K,2151 B,C++

#include<algorithm>  
#include<string.h>  
#include<stdio.h>  
#include<iostream>
#include<set>
#include<map>
#include<string>
#include<vector>
using namespace std;
#define INF 0x3f3f3f3f  
#define maxx(a,b) ((a)>(b)?(a):(b))  
#define minn(a,b) ((a)<(b)?(a):(b))  
#define MAXN 26
#define memset0(a) memset(a,0,sizeof(a))//他现在是宏函数了

struct UF//union find,并查集,复杂是因优化太多,并查集实现很多,不再注释,做成结构体是懒的写析构函数
{
    int UFcnt;
    int sz[MAXN];
    int id[MAXN];
    UF(int N)
    {
        UFcnt = N;
        for (int p = 0; p < N; p++) {
            id[p] = p;
            sz[p] = 1;
        }
    }
    inline int UFfind(int a)
    {
        int p = a;
        while (a != id[a])
            a = id[a];
        id[p] = a;
        return a;
    }
    inline bool UFconnected(int a, int b)
    {
        return UFfind(a) == UFfind(b);
    }
    inline void UFunion(int a, int b)
    {
        int p = UFfind(a);
        int o = UFfind(b);
        if (p == o)
            return;
        else if (sz[p] < sz[o]) {
            id[p] = o;
            sz[o] += sz[p];
        }
        else {
            id[o] = p;
            sz[p] += sz[o];
        }
        UFcnt--;
    }
};
int in[26], out[26];//in degree, out degree,每个字母的入度和出度
bool marked[26];//标识哪些字母用到过,合并并查集时用
char s[1002];//string,临时存放输入字符串
bool f;//flag,就是个标记,下面再解释
void fun(int N)
{
    UF uf(MAXN);//构造一个并查集
    for (int p = 0; p < N; p++) {
        scanf("%s", s);//input
        int a = s[0] - 'a';//a只是随手起的名,将字母转换为数字便于计算
        int b = s[strlen(s) - 1] - 'a';//b也是随手起的,同理
        marked[a] = true;
        marked[b] = true;//这两个字母出现了,标记之
        uf.UFunion(a, b);//将之合并
        out[a]++;//首字母出度加一
        in[b]++;//末字母入度加一<span id="transmark"></span>
    }//input ends here
    int o = -1;
    for (int p = 0; p < MAXN; p++) {//检查所有节点是否连通,即是否都在一棵树内
        if (marked[p] && !f) {//数据中出现过该字母,基准字母没有找到
            o = p;//这个字母就是基准字母
            f = true;//已经找到基准字母
        }
        else if (marked[p] && f&&!uf.UFconnected(o, p)) {//在数据中出现过该字母,基准已找到,但是和基准字母不在一棵树内(图不连通)
            printf("The door cannot be opened.\n");//不连通的图不存在欧拉路/回路
            return;
        }
    }
    int bigin = 0, bigout = 0;//分别记录入度比出度大一和出度比入度大一的节点数,严格卡欧拉路/回路定义,变量名也不难理解
    for (int p = 0; p < MAXN; p++) {
        if (in[p] != out[p]) {//入度出度不等时再深入判断,避免多个else if重复比较
            if (in[p] == out[p]+1)
                bigin++;
            else if(out[p]==in[p]+1)
                bigout++;
            else {//出现了入度和出度相差大于1的情况,这不符合欧拉路/回路的定义
                printf("The door cannot be opened.\n");
                return;
            }
        }
    }
    if ((bigin == 1 && bigout == 1) || (!bigin&&!bigout))//是欧拉路或欧拉回路
        printf("Ordering is possible.\n");
    else
        printf("The door cannot be opened.\n");
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    int times;
    scanf("%d", &times);
    while (times--) {
        int N;
        scanf("%d", &N);
        fun(N);
        memset0(in);
        memset0(out);
        memset0(marked);//这三个现在是宏函数了
        f = false;
    }
}

EOF

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值