#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下节省时间.