算法笔记_148:有向图欧拉回路求解(Java)

目录

1 问题描述

2 解决方案

 


1 问题描述

Description

A catenym is a pair of words separated by a period such that the last letter of the first word is the same as the last letter of the second. For example, the following are catenyms:

dog.gopher
gopher.rat
rat.tiger
aloha.aloha
arachnid.dog

A compound catenym is a sequence of three or more words separated by periods such that each adjacent pair of words forms a catenym. For example,

aloha.aloha.arachnid.dog.gopher.rat.tiger

Given a dictionary of lower case words, you are to find a compound catenym that contains each of the words exactly once.

Input

The first line of standard input contains t, the number of test cases. Each test case begins with 3 <= n <= 1000 - the number of words in the dictionary. n distinct dictionary words follow; each word is a string of between 1 and 20 lowercase letters on a line by itself.

Output

For each test case, output a line giving the lexicographically least compound catenym that contains each dictionary word exactly once. Output "***" if there is no solution.

Sample Input

2
6
aloha
arachnid
dog
gopher
rat
tiger
3
oak
maple
elm

Sample Output

aloha.arachnid.dog.gopher.rat.tiger
***

Source

Waterloo local 2003.01.25

题目链接:http://poj.org/problem?id=2337


2 解决方案

具体代码如下:

package com.liuzhen.practice;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;

public class Main {
    public static int MAX = 30;   //英文字母共26个
    @SuppressWarnings("unchecked")
    public static ArrayList<edge>[] map = new ArrayList[MAX];
    public static String[] path;
    public static int count;  //统计DFS遍历访问的边数目,即检测图的连通性
    public static int start;
    public static int[] inDegree = new int[MAX];
    public static int[] outDegree = new int[MAX];
    public static ArrayList<String> result = new ArrayList<String>();

    class MyComparator implements Comparator<edge> {

        public int compare(edge arg0, edge arg1) {
            String A = arg0.word;
            String B = arg1.word;
            int judge = A.compareTo(B);
            if(judge > 0)
                return 1;
            else if(judge < 0)
                return -1;
            return 0;
        }

    }

    static class edge {
        public int a; //单词的第一个字母序号
        public int b; //单词最后一个字母序号
        public String word;  //具体单词
        public boolean used;     //判断单词是否被访问

        public edge(int a, int b, String word) {
            this.a = a;
            this.b = b;
            this.word = word;
            used = false;
        }
    }

    public void init(int k) {
        start = MAX;
        for(int i = 0;i < MAX;i++) {
            map[i] = new ArrayList<edge>();
            inDegree[i] = 0;
            outDegree[i] = 0;
        }
        path = new String[k];
        for(int i = 0;i < k;i++)
            path[i] = "";
        count = 0;
    }

    public boolean judgeDegree() {
        int in = 0, out = 0;
        for(int i = 1;i < map.length;i++) {  //对map[i]中单词进行字典序排序
            if(map[i].size() > 1)
                Collections.sort(map[i], new MyComparator());
        }

        for(int i = 0;i < inDegree.length;i++) {
            if(inDegree[i] == outDegree[i])
                continue;
            else if(inDegree[i] - outDegree[i] == 1)
                in++;
            else if(outDegree[i] - inDegree[i] == 1) {
                out++;
                start = i;   //此时,可能存在欧拉路径,必须从入度小于出度的点开始遍历
            } else
                return false;
        }
        if(in == out && (in == 0 || in == 1))
            return true;
        return false;
    }

    public void dfs(int begin) {
        for(int i = 0;i < map[begin].size();i++) {
            edge temp = map[begin].get(i);
            if(temp.used == false) {
                temp.used = true;
                path[count++] = temp.word;
                dfs(temp.b);
            }
        }
    }

    public static void main(String[] args) {
        Main test = new Main();
        Scanner in = new Scanner(System.in);
        int t = in.nextInt();
        while(t > 0) {
            t--;
            int k = in.nextInt();
            test.init(k);
            for(int i = 0;i < k;i++) {
                String A = in.next();
                int a = A.charAt(0) - ‘a‘;
                int b = A.charAt(A.length() - 1) - ‘a‘;
                start = Math.min(start, Math.min(a, b));
                map[a].add(new edge(a, b, A));
                outDegree[a]++;
                inDegree[b]++;
            }
            StringBuilder temp = new StringBuilder("");
            if(test.judgeDegree()) {  //满足欧拉回路或者欧拉路径对顶点度的要求
                test.dfs(start);
                if(count == k) {  //图连通
                    for(int i = 0;i < k;i++) {
                        temp.append(path[i]);
                        if(i != k - 1)
                            temp.append(".");
                    }
                } else {
                    temp.append("***");
                }
            } else {
                temp.append("***");
            }
            result.add(temp.toString());
        }
        for(int i = 0;i < result.size();i++)
            System.out.println(result.get(i));
    }
}

运行结果:

2
6
aloha
arachnid
dog
gopher
rat
tiger
3
oak
maple
elm
aloha.arachnid.dog.gopher.rat.tiger
***

参考资料:

1. 欧拉回路

时间: 2024-08-01 11:03:02

算法笔记_148:有向图欧拉回路求解(Java)的相关文章

算法笔记_023:拓扑排序(Java)

目录 1 问题描述 2 解决方案 2.1 基于减治法实现 2.2 基于深度优先查找实现 1 问题描述 给定一个有向图,求取此图的拓扑排序序列. 那么,何为拓扑排序? 定义:将有向图中的顶点以线性方式进行排序.即对于任何连接自顶点u到顶点v的有向边uv,在最后的排序结果中,顶点u总是在顶点v的前面. 2 解决方案 2.1 基于减治法实现 实现原理:不断地做这样一件事,在余下的有向图中求取一个源(source)(PS:定义入度为0的顶点为有向图的源),它是一个没有输入边的顶点,然后把它和所有从它出发

算法笔记_144:有向图强连通分量的Tarjan算法(Java)

目录 1 问题描述 2 解决方案 1 问题描述 引用自百度百科: 如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为强连通分量(strongly connected components). Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树.搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量. 定义D

算法笔记_132:最大流量问题(Java)

目录 1 问题描述 2 解决方案   1 问题描述 何为最大流量问题? 给定一个有向图,并为每一个顶点设定编号为0~n,现在求取从顶点0(PS:也可以称为源点)到顶点n(PS:也可以称为汇点)后,顶点n能够接收的最大流量.图中每条边的权值为该边的容量,从顶点0到顶点n的某一条路径中最大流量不能超过该路径中任何一条边剩下的容量. 2 解决方案 上述对于最大流量问题的描述是楼主自己个人描述,描述的有点粗暴简略>~<. 求取最大流量问题的的核心要理解三个概念: (1)残留网络 (2)增广路径 (3)

算法笔记_027:俄式乘法(Java)

1 问题描述 首先,了解一下何为俄式乘法?此处,借用<算法设计与分析基础>第三版上一段文字介绍: 2 解决方案 具体编码如下: package com.liuzhen.chapter4; public class RussianPeasant { //方法1:递归求解 public void recursionRussian(int m,int n,int result){ if(m < 1) return; if(m == 1) System.out.println("使用递

算法笔记_042:求最小公倍数(Java)

目录 1 问题描述 2 解决方案   1 问题描述 何为最小公倍数?能同时被数字m和数字n整除的最小整数.例如,24和60的最小公倍数等于120.下面请编写相关函数实现求取数字m和n的最小公倍数. 2 解决方案 关于本文求解最小公倍数的思想,来自于<算法设计与分析基础>第三版上一段讲解,具体如下: 具体代码如下: package com.liuzhen.chapter6; public class LeastCommonMultiple { //使用欧几里得算法求解数m和数n最大公约数 pub

算法笔记_124:密码脱落(Java)

一 问题描述 X星球的考古学家发现了一批古代留下来的密码.这些密码是由A.B.C.D 四种植物的种子串成的序列.仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串).由于年代久远,其中许多种子脱落了,因而可能会失去镜像的特征. 你的任务是:给定一个现在看到的密码串,计算一下从当初的状态,它要至少脱落多少个种子,才可能会变成现在的样子. 输入一行,表示现在看到的密码串(长度不大于1000)要求输出一个正整数,表示至少脱落了多少个种子. 例如,输入:ABCBA则程序应该输出:0 再例

算法笔记_016:凸包问题(Java)

目录 1 问题描述 2 解决方案 2.1 蛮力法 1 问题描述 给定一个平面上n个点的集合,它的凸包就是包含所有这些点的最小凸多边形,求取满足此条件的所有点. 另外,形象生动的描述: (1)我们可以把这个问题看作如何用长度最短的栅栏把n头熟睡的老虎围起来. (2)也可以这样看:请把所讨论的点想象成钉在胶合板上的钉子,胶合板代表平面.撑开一根橡皮筋圈,把所有的钉子都围住,然后啪一声松开手.凸包就是以橡皮圈为边界的区域.具体示意如下图1所示: 图1  用橡皮筋来解释凸包 2 解决方案 2.1 蛮力法

算法笔记_225:数字密码发生器(Java)

目录 1 问题描述 2 解决方案   1 问题描述 在对银行账户等重要权限设置密码的时候,我们常常遇到这样的烦恼:如果为了好记用生日吧,容易被破解,不安全:如果设置不好记的密码,又担心自己也会忘记:如果写在纸上,担心纸张被别人发现或弄丢了... 这个程序的任务就是把一串拼音字母转换为6位数字(密码).我们可以使用任何好记的拼音串(比如名字,王喜明,就写:wangximing)作为输入,程序输出6位数字. 变换的过程如下: 第一步. 把字符串6个一组折叠起来,比如wangximing则变为: wa

算法笔记_220:猜算式(Java)

目录 1 问题描述 2 解决方案   1 问题描述 看下面的算式: □□ x □□ = □□ x □□□ 它表示:两个两位数相乘等于一个两位数乘以一个 三位数. 如果没有限定条件,这样的例子很多. 但目前的限定是:这9个方块,表示1~9的9个数字 ,不包含0.该算式中1至9的每个数字出现且只出现一次! 比如:46 x 79 = 23 x 15854 x 69 = 27 x 13854 x 93 = 27 x 186..... 请编程,输出所有可能的情况! 注意:左边的两个乘数交换算同一方案,不要