单词接龙 WordsCanRange --欧拉回路和欧拉路的应用

本文介绍了一种用于判断一组英文单词是否能按照特定规则(每个单词的首字母与前一个单词的尾字母相同)进行接龙的算法。通过构建有向图并使用深度优先搜索判断连通性和欧拉路径的存在性,实现对单词接龙可能性的有效判断。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

拉姆刚开始学习英文单词,对单词排序很感兴趣。如果给拉姆一组单词,他能够迅速确定是否可以将这些单词排列在一个列表中,使得该列表中任何单词的首字母与前一单词的为字母相同。你能编写一个程序来帮助拉姆进行判断吗?


输入描述:
 输入包含多组测试数据。
 对于每组测试数据,第一行为一个正整数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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值