题意:判断能不能把所有单词首尾相连。 能单词相连的部分字母必须相同
思路:其实就是判断欧拉道路的存在性。 每个单词只取首位, 不用保存。 刚看题目以为是拓扑排序。 有点混乱了。
方法一:用并查集判断图的连通性(判断连通性需要把有向图当做无向图来看!)
方法二:用DFS来判断图的连通性。
以上两种方法都要判断度数的合法性: 即 所有vertex 的 in-deg == out-deg,或 有一个点in-deg == out-deg + 1 且 还有一点 in-deg + 1 == out-deg
算法复杂度:未知
代码:
DFS版: 最近不知为何, 欧拉图一用DFS就错, 理解得不深又想优化带来的祸啊。
DFS, 每走过一个点, 标记为走过。 最后判断是不是所有一开始就有的点都走过。
/*DFS判断连通*/
#include <cstdio>
#include <cstring>
using namespace std;
#define MAX_V 26
#define MAX_LEN 1005
int G[MAX_V][MAX_V];
int inDeg[MAX_V];
int outDeg[MAX_V];
int vis[MAX_V];
void DFS(int);
bool okDeg();
bool okDFS();
int main()
{
int cases;
scanf("%d", &cases);
while (cases--) {
// init
memset(G, 0, sizeof(G));
memset(inDeg, 0, sizeof(inDeg));
memset(outDeg, 0, sizeof(outDeg));
memset(vis, 0, sizeof(vis));
int edge, star;
scanf("%d%*c", &edge);
// enter
for (int i = 0; i < edge; i++) {
char str[MAX_LEN];
gets(str);
int u = str[0] - 'a';
int v = str[strlen(str) - 1] - 'a';
outDeg[u]++;
inDeg[v]++;
G[u][v]++;
G[v][u]++;
star = u;
}
// judge
DFS(star);
if (okDeg() && okDFS()) {
printf("Ordering is possible.\n");
}else {
printf("The door cannot be opened.\n");
}
// end a case
}
return 0;
}
void DFS(int u)
{
vis[u] = true;
for (int i = 0; i < MAX_V; i++) {
if (G[u][i] > 0) {
G[u][i]--;
G[i][u]--;
DFS(i);
}
}
}
bool okDeg()
{
bool markStar = false;
bool markEnd = false;
for (int i = 0; i < MAX_V; i++) {
if (inDeg[i] != outDeg[i]) {
if (!markEnd && inDeg[i] == outDeg[i] + 1) {
markEnd = true;
}else if (!markStar && inDeg[i] + 1 == outDeg[i]){
markStar = true;
}else {
return false;
}
}
}
return true;
}
bool okDFS()
{
for (int u = 0; u < MAX_V; u++) {
if (inDeg[u] + outDeg[u]) {
if (vis[u] == false) {
return false;
}
}
}
return true;
}
并查集判连通:
每输入一条边就连接这两个点(如果不会形成环的话), 最后统计所有一开始就有的点, 如果父节点就是这点本身那集合数set就++; set == 1 说明图连通。
/*并查集判连通*/
#include <cstdio>
#include <cstring>
using namespace std;
#define MAX_V 26
#define MAX_LEN 1005
int inDeg[MAX_V];
int outDeg[MAX_V];
int father[MAX_V];
int findFathers(int);
int unite(int, int);
bool okDeg();
int main()
{
int cases;
scanf("%d", &cases);
while (cases--) {
// init
int edge;
scanf("%d%*c", &edge);
memset(inDeg, 0, sizeof(inDeg));
memset(outDeg, 0, sizeof(outDeg));
memset(father, 0, sizeof(father));
for (int i = 0; i < MAX_V; i++) {
father[i] = i;
}
// enter
for (int i = 0; i < edge; i++) {
char str[MAX_LEN];
gets(str);
int u = str[0] - 'a';
int v = str[strlen(str) - 1] - 'a';
inDeg[v]++;
outDeg[u]++;
unite(u, v);
}
// judge deg
if (okDeg()) {
// count set number
// judge a vertex is a set when the vertex exist
int set = 0;
for (int i = 0; i < MAX_V; i++) if (inDeg[i]+outDeg[i]) {
if (father[i] == i) {
set++;
}
}
//judge set
if (set > 1) {
printf("The door cannot be opened.\n");
}else {
printf("Ordering is possible.\n");
}
}else {
printf("The door cannot be opened.\n");
}
}
return 0;
}
int findFathers(int x)
{
if (father[x] != x) {
father[x] = findFathers(father[x]);
return father[x];
}
return x;
}
int unite(int x, int y)
{
x = findFathers(x);
y = findFathers(y);
if (x != y) {
father[x] = y;
}
}
bool okDeg()
{
bool markStar = false;
bool markEnd = false;
for (int i = 0; i < MAX_V; i++) {
if (inDeg[i] != outDeg[i]) {
if (inDeg[i] + 1 == outDeg[i] && !markStar) {
markStar = true;
}else if (inDeg[i] == outDeg[i] + 1 && !markEnd) {
markEnd = true;
}else {
return false;
}
}
}
return true;
}