标签:
题目链接:点击打开链接
题意:
把输入的n个由小写字母构成的字符串连成字典序最小的一句话,使得所有字符串都恰好出现一次且相邻两个字符串相邻的字母相同
思路:
比如abcd,我们认为是这样一条边:a->d
所以我们在a->d间建一条边。
1、如:abcd, dfgh,
那么得到的边就是 a->d, d->h。
而题目的目标是每个字符串恰好用一次,即每条边恰好用一次。也就是找一条欧拉通路
2、我们只需要关心字符串的首尾2个字母,所以我们认为图里只有26个节点。
3、判断欧拉通路是否存在:
保证图是连通的。
保证图里要么(每个点入度=出度,此时路径的起点任意)要么(恰好一个点入度为1,同时恰好一个点出度为1,此时路径的起点只能为出度为1的点)
4、寻找欧拉通路:
因为(3)中已经保证欧拉通路存在,则我们随便找一条就可以了
dfs时顺便记录经过的边(注意记录的是边而不是点)
输出路径时把记录的边逆序输出即可。
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Scanner;
import java.util.Stack;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.Queue;
public class Main {
class Node implements Comparable<Node>{
int v, vis;
String str;
Node(){}
Node(int v, int vis, String str){
this.v = v;
this.vis = vis;
this.str = str;
}
public int compareTo(Node o) {
return this.str.compareTo(o.str);
}
}
int n;
ArrayList<Node>[] G = new ArrayList[Maxn];
Stack<String> stack = new Stack();
int[] vis = new int[Maxn], f = new int[Maxn], In = new int[Maxn], Out = new int[Maxn];
int find(int x){return (x==f[x])?x:(f[x]=find(f[x]));}
void Union(int x, int y){
int fx = find(x), fy = find(y);
if(fx == fy)return ;
f[fx] = fy;
}
void find_path(int u){
for (int i = 0; i<G[u].size(); i++)
{
int v = G[u].get(i).v;
if (0 == G[u].get(i).vis)
{
G[u].get(i).vis = 1;
find_path(v);
stack.push(G[u].get(i).str);
}
}
}
void print(){
out.print(stack.pop());
while(!stack.isEmpty())
out.print("."+stack.pop());
out.println();
}
int id;//id为起点编号
boolean euler_formula(){
int cnt_big = 0, cnt_less = 0; id = -1;
for (int i = 0; i<26; i++)
if (vis[i] == 1)
{
if (In[i] == Out[i])continue;
if (In[i] - Out[i] == 1)cnt_big++;
else if (In[i] - Out[i] == -1){cnt_less++; id = i;}
else return false;
}
if (false == (cnt_big == 1 && cnt_less == 1) && false == (cnt_big == 0 && cnt_less == 0))return false;
int cnt = 0; //图的联通块个数必须为1
for(int i = 0; i < Maxn; i++)
if(vis[i] == 1 && f[i] == i)cnt++;
return cnt == 1;
}
void add(int u, int v, String str){
Out[u] ++; In[v] ++;
vis[u] = vis[v] = 1;
Node E = new Node(v, 0, str);
G[u].add(E);
Union(u, v);
}
void init(){
for(int i = 0; i < Maxn; i++){
f[i] = i;
vis[i] = In[i] = Out[i] = 0;
G[i].clear();
}
stack.clear();
}
void input(){
init();
n = cin.nextInt();
for(int i = 1; i <= n; i++)
{
String s = "";
while(s.length()==0 || s.charAt(0)<'a'||s.charAt(0)>'z')s = cin.next();
int u = s.charAt(0)-'a', v = s.charAt(s.length()-1)-'a';
add(u, v, s);
}
for(int i = 0; i < Maxn; i++) Collections.sort(G[i]); //排序保证字典序最小
}
void work() {
for(int i = 0; i < Maxn; i++) G[i] = new ArrayList();
int T = cin.nextInt();
while(T-->0){
input();
if(euler_formula()){
if(id == -1)
for(int i = 0; i < 26 && id == -1; i++)
if(vis[i] == 1)
id = i;//若每个点出度=入度则起点任取
find_path(id);
print();
}
else out.println("***");
}
}
Main() {
cin = new Scanner(System.in);
out = new PrintWriter(System.out);
}
public static void main(String[] args) {
Main e = new Main();
e.work();
out.close();
}
public Scanner cin;
public static PrintWriter out;
static int Maxn = 26;
}
标签:
原文地址:http://blog.csdn.net/qq574857122/article/details/43270273