poj-1386

// 1148K    360MS   G++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define CHAR_NUM 26

char UF_array[CHAR_NUM];

struct CharNodeDegree {
    int inDegree;
    int outDegree;
    char used;
};

struct InputWord {
    int beginChar;
    int endChar;
};

typedef struct CharNodeDegree CharNodeDegree;
typedef struct InputWord InputWord;

CharNodeDegree nodesDegree[CHAR_NUM];
InputWord inputWord[100010];

#define BEGIN_CHAR 'a'

int UF_setNum = 0;

//mege child set in parent set
char UF_merge(int parent, int child) {
    UF_array[child] = parent;
    UF_setNum--;
}

char UF_getRoot(int nodeId) {
    while(UF_array[nodeId] != nodeId) {
        nodeId = UF_array[nodeId];
    }
    return nodeId;
}

void UF_add(int from, int to) {
// also is a directed graph, but for connectivity check,
// as a undirected graph
    if (UF_array[from] == -1 && UF_array[to] == -1) { // both belong new set
        UF_array[to] = to;
        UF_array[from] = to;
        UF_setNum++;
    } else if (UF_array[from] == -1) { // add from to 'to''s set
        UF_array[from] = UF_getRoot(to);
        UF_array[to] = UF_array[from];
    } else if (UF_array[to] == -1) { // add 'to' to from's set
        UF_array[to] = UF_getRoot(from);
        UF_array[from] = UF_array[to];
    } else { // may belong to same/different sets
        char fromRoot = UF_getRoot(from);
        char toRoot = UF_getRoot(to);
        if (fromRoot != toRoot) { // belong to differents sets
            UF_merge(fromRoot, toRoot);
            UF_array[to] = fromRoot;
            UF_array[from] = toRoot;
        }
    }
}

char existEulerPath() {
    int OutMore1ThanTo = 0;
    int ToMore1ThanOut = 0;;
    for (int i = 0; i < CHAR_NUM; i++) {
        if (nodesDegree[i].used) {
            if (abs(nodesDegree[i].outDegree
                    - nodesDegree[i].inDegree) > 1) {
                // printf("1 %d %d\n", nodesDegree[i].outDegree, nodesDegree[i].inDegree);
                return 0;
            } else if (nodesDegree[i].outDegree
                        != nodesDegree[i].inDegree) {
                nodesDegree[i].outDegree > nodesDegree[i].inDegree ?
                    OutMore1ThanTo++ : ToMore1ThanOut++;
                if (OutMore1ThanTo > 1 || ToMore1ThanOut > 1 || (OutMore1ThanTo + ToMore1ThanOut) > 2) {
                    // printf("2 %d %d\n", nodesDegree[i].outDegree, nodesDegree[i].inDegree);
                    return 0;
                }
            }
        }
    }
    return ((OutMore1ThanTo == 1 && ToMore1ThanOut == 1) ||
        (OutMore1ThanTo == 0 && ToMore1ThanOut == 0));
}

int main() {

    int caseNum = 0;
    char word[1002] = {0};
    scanf("%d", &caseNum);
    for (int i = 0; i < caseNum; i++) {
        int wordNum = 0;
        scanf("%d", &wordNum);
        memset(nodesDegree, 0, sizeof(nodesDegree));
        memset(UF_array, -1, sizeof(UF_array));
        memset(inputWord, 0, sizeof(inputWord));
        UF_setNum = 0;
        for (int j = 0; j < wordNum; j++) {
            scanf("%s", word);
            int from = word[0] - BEGIN_CHAR;
            int to = word[strlen(word)-1] - BEGIN_CHAR;
            // UF_add(from, to);
            nodesDegree[from].used = 1;
            nodesDegree[to].used = 1;
            (nodesDegree[from].outDegree)++;
            (nodesDegree[to].inDegree)++;
            inputWord[j].beginChar = from;
            inputWord[j].endChar = to;
        }
        if (wordNum <= 1) {
            printf("Ordering is possible.\n");
            continue;
        }
        if (existEulerPath()) {
            // printf("connected\n");
            for (int i = 0; i < wordNum; i++) {
                UF_add(inputWord[i].beginChar, inputWord[i].endChar);
            }
            UF_setNum == 1 ? printf("Ordering is possible.\n")
                            : printf("The door cannot be opened.\n");
        } else {
            printf("The door cannot be opened.\n");
        }
    }

}

360MS   G++

与2513一个思路,并且因为输入的简化,因此连tire树都不需要了,趁热打铁,就当深化并查集和欧拉路,顺手解了。

这道题与2513的不同之处在于,从无向图变成了有向图(题目这次要求单词首位相接,而单词本身的排列是不能倒置的,比如,

2513 stick是没有前后的, red<-->blue 也可以看做 blue<-->red, 但这道题的单词则是分先后的, acm 就不能当 mca用,这两个完全是不同的单词),acm这个单词

只能表示从'a'到‘m’可达,但是‘m’到‘a’并不可达,因此判断欧拉路径就要按照有向图的规则:

有向图G具有 单向欧拉路,当且仅当它是连通的,而且除两个结点外,每个结点的入度等于出度,但这两个结点中,一个结点的入度比出度大1,另一个结点的入度比出度小1。
D是一个有向图,如果略去D中各有向边的方向后所得无向图G是连通图,则称D连通图,或称D弱连通图

从上面两个规则看,还是之需要有并查集检查连通性然后检测每个节点的出入度就可以,因为有向图是否连通可以将其转化为相应的无向图连通,因此并查集还可以work。

然后检测出入度,要记得欧拉路径存在条件是全部的节点出度等于入度,或是一个节点 出=入+ 1, 一个节点入 = 出+1, 忘了判断全部等,WA了一次..

还有,如果先并查集检测连通,然后欧拉检测,会TLE,

因此最好先欧拉检测(时间短),如果通过,再并查集检测连通,这样能在某些欧拉都通不过的case下节省时间.


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值