思路:明显的有向联通图,关键是判断是否存在欧拉道路
题目只是要求输出是否可能,不要求输出排序结果
要判断有向图的欧拉道路,首先要判断它的基图,也就是没有方向是否的图,是否联通,
如果联通,再判断输入输出度数
对于欧拉回路,要求苛刻一点,所有点的入度都要等于出度,那么就存在欧拉回路了
对于欧拉道路,要求松一点,只有一个点,出度比入度大1,这个点一定是起点; 一个点,入度比出度大1,这个点一定是终点.其余点的出度等于入度
网上很多思路都非常乱,我们还是按照传统的一步一步来,用dfs()统计图是否联通
package test;
import java.util.Arrays;
import java.util.Scanner;
public class Test{
static Scanner sc = new Scanner(System.in);
static String line;
static int n = 26;//26个字母
/*
* 有向图,代表一个单词开头指向结尾n->n,因为我们要借用无向图来判断是否联通,所以存储了a->b以后,还有存储b->a,从而使有向转换为无向
*/
static int[][] G = new int[n][n];
static boolean[] vis = new boolean[n];//记录26个字母是否联通
static int[] in = new int[n];//记录入度
static int[] out = new int[n];//记录出度
/**
* 将字符转换成对应数字
* @param c
* @return
*/
static int char_int(char c){
return c-'a';
}
/**
* 使用dfs,设置vis数组,用于后面检验26个字母是否联通(也就是图是否联通)
* @param u
*/
static void euler(int u){
vis[u] = true;
for(int v=0;v<n;v++){
if(G[u][v]>0){
G[u][v]--;//以为当成无向图看待,其实就是两个有向图,所以要去除两个方向
G[v][u]--;//
euler(v);
}
}
}
/**
* 检查vis数组,判断图是否联通
* @return
*/
static boolean checkDfs(){
for (int u = 0; u < n; u++) {
if (in[u] + out[u]>0) {
if (vis[u] == false) {
return false;
}
}
}
return true;
}
/**
* 检查出入度是否符合规则
* @return
*/
static boolean checkDeg(){
boolean flag=true;
int num1=0,num2=0;
for(int i=0;i<n;i++){
if(!flag) break;
if(in[i]!=out[i]){
if(in[i]==out[i]+1) { ++num1; }
else if(out[i]==in[i]+1) { ++num2; }
else {flag=false; break; }
}
}
if(num1>=1 && num2>=1 && num1+num2>2) flag=false;
return flag;
}
public static void main(String[] args) {
/*
* 输入
*/
while(!"".equals((line=sc.nextLine()))){
G[char_int(line.charAt(0))][char_int(line.charAt(line.length()-1))]++;
G[char_int(line.charAt(line.length()-1))][char_int(line.charAt(0))]++;
in[char_int(line.charAt(0))]++;
out[char_int(line.charAt(line.length()-1))]++;
}
Arrays.fill(vis, false);
euler(0);
if(checkDfs() && checkDeg()){
System.out.println("成功");
}else{
System.out.println("失败");
}
}
}