本题...看的是刘汝佳的书,本来一开始以为是用单词作为结点,然后直接dfs遍历来着...但是发现这样做超时了。。。
超时代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while(t-->0) {
int n = in.nextInt(); //n个单词
String[] words = new String[n];
in.nextLine();
int i= 0;
for(; i < n; i++)
words[i] = in.nextLine();
i = 0;
for(; i < n; i++) {
int cnt = 0;
int[] vis = new int[n];
int pre = -1; //记录第i结点的前一个下标,-1表示i是第一个放入的结点
if(check(words,i,vis,pre,++cnt)) {
System.out.println("Ordering is possible.");
break;
}
}
if(i==n) {
System.out.println("The door cannot be opened.");
}
}
}
/**
* 检查words[x]是否符合条件
* @param words
* @param x
* @param vis
* @param cnt 第几个放入的点
* @return
*/
public static boolean check(String[] words, int x, int[] vis, int pre, int cnt) {
if(vis[x]==1) //如果x结点被访问,则直接退出
return false;
//如果words是第一个放入的结点
if(pre<0) {
vis[x] = 1; //放入结点x
pre = x;
for(int i = 0; i < words.length; i++) {
if(check(words,i,vis,pre,++cnt))
return true;
}
return false;
}
//如果x前面有结点,则需要检查是否符合条件
int preLength = words[pre].length();
char p = words[pre].charAt(preLength-1); //前一个结点的最后一个字母
int index = pre; //记录下pre的值,方便回溯
char xOfFirst = words[x].charAt(0);//结点x的第一个字母
if(p==xOfFirst) { //如果结点x和上一个结点符合条件
if(cnt==words.length)
return true;
vis[x] = 1;
pre = x;
//遍历
for(int i = 0; i < words.length; i++) {
if(check(words,i,vis,pre,++cnt))
return true;
}
//要是遍历完没发现则回溯
vis[x] = 0;
pre = index;
cnt--;
return false;
}
return false;
}
}
发现原题中n的取值是[1,100000],这才觉得不超时才怪。。。
正确代码正在研究网上大佬的,有空再更。