-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathP10129.cpp
158 lines (150 loc) · 3.91 KB
/
P10129.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// This is a simple question of checking if a graph has an Euler path.
// We can check if a graph has an euler path by connecting the start and end edge and instead ask if it has an Euler cycle.
// A graph has an euler cycle if all nodes have inDegree=outDegree and are strongly connected.
int inDegree[26], outDegree[26];
bool connects[26][26]; // [a][b] iff a->b
bool connectsReverse[26][26]; // [a][b] iff b->a
// Mark the reachable nodes.
void dfsMark(int x, bool *reachable, bool g[][26]) {
FORI(26) {
if(i == x)
continue;
if(reachable[i])
continue; // Already visited.
if(!g[x][i])
continue; // No edge.
reachable[i] = true;
dfsMark(i, reachable, g);
}
}
// Use "Kosaraju using DFS":
bool isStronglyConnected() {
bool reachable[26];
bool reachableReverse[26];
FORI(26)
reachableReverse[i] = reachable[i] = false;
// Find starting node:
int start = -1;
FORI(26) {
if(inDegree[i] != 0) {
start = i;
break;
}
}
if(start == -1) {
//cerr << "EMPTY GRAPH" << endl;
return true; // Empty graph.
}
/*
//cerr << "CONNECTS:" << endl;
FORI(26) {
if(inDegree[i] == 0)
continue;
//cerr << ((char)('a'+i)) << " ->";
FORJ(26) {
if(connects[i][j])
//cerr << " " << ((char)(j+'a'));
}
//cerr << endl;
}
//cerr << "REVERSE:" << endl;
FORI(26) {
if(inDegree[i] == 0)
continue;
//cerr << ((char)('a'+i)) << " ->";
FORJ(26) {
if(connectsReverse[i][j])
//cerr << " " << ((char)(j+'a'));
}
//cerr << endl;
}
//*/
reachable[start] = reachableReverse[start] = true;
dfsMark(start, reachable, connects);
dfsMark(start, reachableReverse, connectsReverse);
FORI(26) {
if(inDegree[i] == 0)
continue;
if(!reachable[i]) {
//cerr << (char)(i+'a') << " not reachable from " << ((char)(start+'a')) << endl;
return false;
}
if(!reachableReverse[i]) {
//cerr << (char)(i+'a') << " not REVERSE reachable from " << ((char)(start+'a')) << endl;
return false;
}
}
return true;
}
bool hasEulerPath() {
int start = -1;
int end = -1;
// Find start and end:
FORI(26) {
if(inDegree[i] == outDegree[i]) {
// OK!
}
else if(inDegree[i] == outDegree[i]+1) {
if(end != -1) {
//cerr << "Two end nodes! " << ((char)(end+'a')) << " and " << ((char)(i+'a')) << endl;
return false; // More than one end.
}
end = i;
}
else if(inDegree[i] == outDegree[i]-1) {
if(start != -1) {
//cerr << "Two start nodes! " << ((char)(start+'a')) << " and " << ((char)(i+'a')) << endl;
return false; // More than one start.
}
start = i;
}
else {
//cerr << "More than one in difference for " << ((char)(i+'a')) << ": in degree " << inDegree[i] << ", out degree: " << outDegree[i] << endl;
return false; // More than one in difference!
}
}
if(start == -1 && end == -1) {
// Any start and end will do!
}
else if(start == -1 || end == -1) {
//cerr << "This should not happen!" << endl;
return false; // Bad state!
}
else {
// There is a distinct start and end... so we just connect end->start and ask if there is an euler cycle instead :)
++outDegree[end];
++inDegree[start];
connects[end][start] = true;
connectsReverse[start][end] = true;
}
return isStronglyConnected();
}
int main() {
FORCAS {
// Reset data structures:
FORI(26) {
inDegree[i] = outDegree[i] = 0;
FORJ(26) {
connects[i][j] = false;
connectsReverse[i][j] = false;
}
}
// Read data:
GI(N);
FORI(N) {
GS(s);
int from = s[0]-'a';
int to = s[s.size()-1]-'a';
++outDegree[from];
++inDegree[to];
connects[from][to] = true;
connectsReverse[to][from] = true;
}
// Compute:
if(hasEulerPath())
cout << "Ordering is possible." << endl;
else
cout << "The door cannot be opened." << endl;
}
return 0;
}