题目:
拉姆刚开始学习英文单词,对单词排序很感兴趣。如果给拉姆一组单词,他能够迅速确定是否可以将这些单词排列在一个列表中,使得该列表中任何单词的首字母与前一单词的为字母相同。你能编写一个程序来帮助拉姆进行判断吗?
输入描述:
输入包含多组测试数据。
对于每组测试数据,第一行为一个正整数n,代表有n个单词。 然后有n个字符串,代表n个单词。
保证: 2<=n<=200,每个单词长度大于1且小于等于10,且所有单词都是由小写字母组成。
输出描述:
对于每组数据,输出"true"或"false"
输入例子:
3
abc
cdefg
ghijkl
4
abc
def
fghijk
xyz
输出例子:
true
false
import java.util.Scanner;
public class WordsCanRange {
// 一个连通( 弱连通) 有向图具有欧拉回路的充要条件是 G 的每一个结点的入度和出度相等。
// 具有欧拉路的充要条件是除两个结点外,每个结点的入度等于出度。
// 对于这两个结点,一个 结点的出度比入度多 1 ,另一个结点的出度比入度 少1。
public static boolean mySolution(int n, String[] words) {
// 特殊情况处理
if (n <= 0 || words == null || words.length == 0) {
return false;
}
// edge是个二维数组,
// 当edge[i] [j] =1 时表示有从 j 到i 的一条弧,
// 当edge[i] [j] =0 时则表示没有。
int edge[][] = new int[26][26];
// in 是一个一维数组, in[i] =x 表示i 点的入度为x 。
int inDegree[] = new int[26];
// out是一个一维数组, out[i] =x 表示i 点的出度为x 。
int outDegree[] = new int[26];
// visited 是个一维数组,
// 当visited[i] =1时表示 i点已经被访问到了。
// 当visited[i] =0 时表示 i 点没有被访问到。
boolean visited[] = new boolean[26];
while (n > 0) {
inDegree[words[n - 1].charAt(0) - 'a']++;
outDegree[words[n - 1].charAt(words[n - 1].length() - 1) - 'a']++;
edge[words[n - 1].charAt(0) - 'a'][words[n - 1].charAt(words[n - 1].length() - 1) - 'a'] = 1;
n--;
}
//
boolean headFind = false;// 头结点存在标志
boolean tailFind = false;// 尾节点存在标志
boolean wordsCanRange = true;
if (isConected(edge, visited)) {// 如果有向图是弱连通的
// 循环检查所有点的入度和出度
for (int i = 0; i < visited.length; i++) {
// 如果该点的度不为0
if (inDegree[i] + outDegree[i] != 0) {
if (headFind == false && outDegree[i] - inDegree[i] == 1) {
// 找到出度比入度多 1的头结点
headFind = true;
} else if (inDegree[i] - outDegree[i] == 1 && tailFind == false) {
// 找到出度比入度 少1的尾结点
tailFind = true;
} else if (outDegree[i] == inDegree[i]) {
// 出度等于入度相等则继续检查下一个节点
continue;
} else {
// 除两个特殊点外还存在入度与出度不相等的点,
// 这说明既不存在欧拉回路也不存在欧拉路
wordsCanRange = false;
}
}
}
} else {// 如果有向图不是是弱连通的则单词组不能接龙
wordsCanRange = false;
}
if (wordsCanRange) {
return true;
} else {
return false;
}
}
// 利用深度优先遍历(dfs) 判断改图是否是弱联通的
private static boolean isConected(int[][] edge, boolean[] visited) {
int connection_count = 0;
for (int i = 0; i < edge.length; i++) {
for (int j = 0; j < edge[0].length; j++) {
if (edge[i][j] == 1 && visited[i] == false) {
// 从i点开始深度搜索,知道无路可走
dfs(i, edge, visited);
// 统计连通分量个数
connection_count++;
}
}
}
if (connection_count == 1) {
return true;
} else {
return false;
}
}
// 深度优先遍历图
private static void dfs(int i, int[][] edge, boolean[] visited) {
visited[i] = true;
for (int j = 0; j < visited.length; j++) {
// 标记与i节点相关的节点,出或者入
if (visited[j] == false && edge[i][j] == 1) {
dfs(j, edge, visited);
}
if (visited[j] == false && edge[j][i] == 1) {
dfs(j, edge, visited);
}
}
return;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan = new Scanner(System.in);
while (scan.hasNext()) {
int n = scan.nextInt();
String[] words = new String[n];
for (int i = 0; i < n; i++)
words[i] = scan.next();
System.out.println(mySolution(n, words));
}
scan.close();
}
}
参考论文:http://www.cnki.com.cn/Article/CJFDTotal-BJLH200503006.htm