Java实现Catenyms(并查集+dfs+欧拉回路)

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


中文说明

类义词是由句号分隔的一对词,第一个词的最后一个字母与第二个词的最后一个字母相同。例如,以下是类别名称:

狗。地鼠

地鼠

老鼠,老虎

阿罗哈,阿罗哈

蛛形纲动物

复合词义是由三个或三个以上的单词组成的序列,这些单词之间用句点隔开,从而使每对相邻的单词形成一个词义。例如,

阿罗哈。阿罗哈。蛛形纲动物。狗。地鼠。老虎。

给定一个小写单词的字典,您将找到一个复合的catenym,它只包含每个单词一次。

输入

标准输入的第一行包含t,即测试用例的数量。每个测试用例以3<=n<=1000-字典中的单词数开始。后面有n个不同的字典单词;每个单词本身就是一行上1到20个小写字母之间的字符串。

输出

对于每一个测试用例,输出一行,给出字典式最小复合类别名,该类别名恰好包含每个字典单词一次。如果没有解决方案,则输出“***”。

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));
    }
}

运行结果:

6
aloha
arachnid
dog
gopher
rat
tiger
oak
maple
elm
aloha.arachnid.dog.gopher.rat.tiger
***
  • 18
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
package hamierton; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Random; public class EularCircuit { public EularCircuit() { } public static void main(String[] args) { // System.out.println("please input n:"); // BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = 4; try { // n = Integer.parseInt(br.readLine()); } catch (Exception ex) { return; } try { Graph g = new Graph(n); g.printg(); g.circuit(); } catch (Exception e) { System.out.println(e.toString()); e.printStackTrace(); return; } } } class Node { private static int count = 0; private String name; private ArrayList adjacencyList; private boolean visited =false; public Node() { name = "node " + count; adjacencyList = new ArrayList(); } public Node(String name) { this.name = name; adjacencyList = new ArrayList(); } public boolean isAllVisited() { for (int i = 0; i < adjacencyList.size(); i++) { SNode sn = (SNode) adjacencyList.get(i); if (sn.visited == false) { return false; } } return true; } public boolean isvisited(){ return visited; } public void setvisited(){ visited = true; } public int getAdjacencyCount() { return adjacencyList.size(); } public boolean contains(int i) { return this.adjacencyList.contains(new SNode(i)); } public void removeAdjacencyNode(int i) { this.adjacencyList.remove(new SNode(i)); } public void addAdjacencyNode(int i) { this.adjacencyList.add(new SNode(i)); } public SNode getAdjacencyNode(int i) { return (SNode) this.adjacencyList.get(i); } public SNode getAdjacencyNodeEX(int i_ref) { for (int i = 0; i < this.getAdjacencyCount(); i++) { if (getAdjacencyNode(i).index == i_ref) { return getAdjacencyNode(i); } } return null; } public String toString() { return this.name; } } class SNode { public boolean visited = false; public int index = 0; public SNode(int index) { this.index = index; } public boolean equals(Object o) { if (((SNode) o).index == this.index) { return true; } return false; } public String toString() { return "adjacency " + index; } } class Graph { private ArrayList nodeList; private ArrayList path; private int count; public Graph(int n) throws Exception { this.count = n; nodeList = new ArrayList(count); ginit(); } public void circuit() { path = new ArrayList(); int top = 0; int k = 0; path.add(new Integer(0)); while (true) { int i, j; i = top; ArrayList path1 = new ArrayList(); path1.add(new Integer(top)); while (true) { Node node = (Node) nodeList.get(i); for (j = 0; j < this.count; j++) { if (node.contains(j) && node.getAdjacencyNodeEX(j).visited == false) { path1.add(new Integer(j)); node.getAdjacencyNodeEX(j).visited = true; // ((Node) nodeList.get(j)).getAdjacencyNodeEX(i).visited = true; i = j; break; } } if (i == top) { break; } } path.remove(k); path.addAll(k, path1); k++; if (k >= path.size()) { break; } top = ((Integer) path.get(k)).intValue(); } for (int z = 0; z < path.size(); z++) { System.out.print(path.get(z).toString() + " "); } } private void ginit() { int i; for (i = 0; i < 4; i++) { nodeList.add(new Node("node" + i)); } ((Node)nodeList.get(0)).addAdjacencyNode(3); ((Node)nodeList.get(1)).addAdjacencyNode(0); ((Node)nodeList.get(2)).addAdjacencyNode(1); ((Node)nodeList.get(3)).addAdjacencyNode(2); // ((Node)nodeList.get(0)).addAdjacencyNode(3); // ((Node)nodeList.get(1)).addAdjacencyNode(0); // ((Node)nodeList.get(2)).addAdjacencyNode(1); // ((Node)nodeList.get(3)).addAdjacencyNode(2); // for (i = 0; i < n; i++) { // nodeList.add(new Node("node" + i)); // } // ArrayList linked = new ArrayList(); // linked.add(new Integer(0)); // Random rand = new Random(); // // for (i = 1; i < n; i++) { // int size = linked.size(); // // int top = ((Integer) (linked.get(size - 1))).intValue(); // Node node = (Node) (nodeList.get(top)); // // while (true) { // int randint = rand.nextInt(n); // if (randint == top) { // continue; // } // if (node.contains(randint)) { // continue; // } else { // if (!linked.contains(new Integer(randint))) { // linked.add(new Integer(randint)); // } else if (node.getAdjacencyCount() >= (linked.size() - 1 > 6 ? 6 // : linked.size() - 1)) { // continue; // } else { // i--; // } // node.addAdjacencyNode(randint); // Node randnode = (Node) nodeList.get(randint); // randnode.addAdjacencyNode(top); // break; // } // } // } // // for (i = 0; i < this.count - 1; i++) { // Node node = (Node) nodeList.get(i); // if (node.getAdjacencyCount() % 2 != 0) { // int j = 0; // for (j = i + 1; j < this.count; j++) { // Node nn = (Node) nodeList.get(j); // if (nn.getAdjacencyCount() % 2 != 0) { // if (node.contains(j)) { // // if (nn.getAdjacencyCount() != 1 // && node.getAdjacencyCount() != 1) { // node.removeAdjacencyNode(j); // nn.removeAdjacencyNode(i); // break; // } else { // continue; // } // } else { // // node.addAdjacencyNode(j); // nn.addAdjacencyNode(i); // break; // } // } // } // // if (j == this.count) { // int k; // Node nk = null; // for (k = i + 1; k < this.count; k++) { // // nk = (Node) nodeList.get(k); // if (nk.getAdjacencyCount() % 2 != 0) { // break; // } // } // int kk = k; // for (k = 0; k < i; k++) { // Node n1 = (Node) nodeList.get(k); // if (!n1.contains(kk) && !n1.contains(i)) { // n1.addAdjacencyNode(kk); // nk.addAdjacencyNode(k); // n1.addAdjacencyNode(i); // node.addAdjacencyNode(k); // break; // } // } // boolean retry = false; // // if (k == i) { // int vv; // for (vv = 0; vv < this.count; vv++) { // Node vn = (Node) nodeList.get(vv); // if (!vn.contains(i) && i != vv) { // vn.addAdjacencyNode(i); // node.addAdjacencyNode(vv); // retry = true; // break; // } // } // if (vv == count) { // for (vv = 0; vv < count; vv++) { // Node vnn = (Node) nodeList.get(vv); // if (vnn.getAdjacencyCount() > 1) { // vnn.removeAdjacencyNode(i); // node.removeAdjacencyNode(vv); // retry = true; // break; // } // } // } // } // if (retry) { // i = -1; // } // } // } // // } // return this.isEularG(); } public boolean isEularG() { boolean isEular = true; for (int i = 0; i < this.count; i++) { Node n = (Node) nodeList.get(i); if (n.getAdjacencyCount() % 2 != 0) { isEular = false; break; } } return isEular; } public void printg() { for (int i = 0; i < this.count; i++) { Node n = (Node) nodeList.get(i); System.out.print(n.toString() + " "); for (int j = 0; j < n.getAdjacencyCount(); j++) { System.out.print(n.getAdjacencyNode(j).toString() + " "); } System.out.println(); } } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值