【发布时间】:2020-02-23 14:13:37
【问题描述】:
问题链接:https://www.spoj.com/problems/PPATH/
问题的简要说明,
1) Construct a graph with prime numbers between 1000 and 9999.
2) Add an undirected edge between two numbers 'a' and 'b', if they differ only by one digit.
EX: 1033 and 1733 differ only by one digit.
3) In that graph we need to find the length of the shortest path from the given source to the given destination.
我已经解决了上述问题,方法是使用 1000 到 9999 之间的质数,通过连接仅相差一位数的数字来构建图形。例如:1033 和 1733 仅相差一位。 我已经使用 DFS 和记忆来找到最短路径。 对于某些输入,我得到了错误的答案,比实际值大 1,因为有 1000 个节点我无法找出问题所在。如果有人帮助我解决问题,那将非常有帮助。
我知道这个问题可以通过 BFS 解决,但我需要知道这个问题有什么问题。
以下程序打印错误答案时的测试用例
1
7573 9973
实际答案:4
我的代码输出:5
(我通过提交 BFS 方法找到了实际答案,并在 SPOJ 中被接受)。
import java.util.*;
import java.lang.*;
import java.io.*;
class FireEscapeRoutes_FIRESC {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws Exception{
int t = 1;
while (t--!=0){
int source = 7573;
int destination = 9973;
List<Integer> fourDigitPrimeNos = new ArrayList<>();
for(int i=1001;i<=9999;i++){
if(isPrime(i)){
fourDigitPrimeNos.add(i);
//System.out.println(i);
}
}
Graph graph = new Graph(fourDigitPrimeNos.size());
/*
If two number 'a' and 'b' differ only by one digit then an edge is added.
*/
for (int i=0;i<fourDigitPrimeNos.size();i++){
for (int j=i+1;j<fourDigitPrimeNos.size();j++){
if(isSingleDistnace(fourDigitPrimeNos.get(i),fourDigitPrimeNos.get(j))){
graph.add(fourDigitPrimeNos.get(i),fourDigitPrimeNos.get(j));
}
}
}
//System.out.println(graph.graph);
Long minPath = graph.getShortestPath(source,destination);
if(minPath!=Long.MAX_VALUE){
System.out.println(minPath);
}else{
System.out.println("Impossible");
}
}
}
static boolean isSingleDistnace(int a, int b){
String as = a+"";
String bs = b+"";
int ds = 0;
for (int i=0;i<as.length();i++){
if(!(as.charAt(i)==bs.charAt(i))){
if(ds>=1){
return false;
}
ds++;
}
}
if(ds==0){
return false;
}
return true;
}
static boolean isPrime(int n){
for (int i=2;i<=Math.sqrt(n);i++){
if(n%i==0){
return false;
}
}
return true;
}
}
class Graph{
int noOfVertices;
HashMap<Integer,List<Integer>> graph;
Graph(int v){
noOfVertices = v;
graph = new HashMap<Integer,List<Integer>>();
}
void add(int u,int v){
if (!graph.containsKey(u)){
graph.put(u,new ArrayList<>());
}
if(!graph.containsKey(v)){
graph.put(v,new ArrayList<>());
}
graph.get(u).add(v);
graph.get(v).add(u);
}
Long getShortestPath(int start, int dest){
HashMap<Integer,Long> visitedVsMinCost = new HashMap<>();
Long min = Long.MAX_VALUE;
min = getShortestPathUtil(start,dest,visitedVsMinCost);
return min-1;
}
Long getShortestPathUtil(Integer start,Integer dest,HashMap<Integer,Long> visitedVsMinCost){
if(start.equals(dest)){
return 1l;
}
visitedVsMinCost.put(start, Long.MAX_VALUE);
List<Integer> frnds = graph.get(start);
Long min = Long.MAX_VALUE;
for (Integer iThFrind:frnds){
if(!visitedVsMinCost.containsKey(iThFrind)){
Long shortestPathUtil = getShortestPathUtil(iThFrind, dest, visitedVsMinCost);
//System.out.println(shortestPathUtil + " min " + min);
min = Math.min(min, shortestPathUtil);
}else {
if(!visitedVsMinCost.get(iThFrind).equals(Long.MAX_VALUE)) {
min = Math.min(min, visitedVsMinCost.get(iThFrind)+1);
}
}
}
visitedVsMinCost.put(start,min);
//System.out.println(min);
if (min.equals(Long.MAX_VALUE)){
return min;
}
return min+1;
}
}
注意:下面的部分是为了解释为什么我的代码在@c0der 提到的情况下工作。由于我无法评论更多字符,我正在编辑这个问题。要了解方法,您可以使用以下部分。
我可以理解调试代码很困难,所以我尝试使用@coder 回答和提到的图表来解释我的方法 上面的代码在你提到的场景中工作正常。
起点 = 1,终点 = 5,最短路径 = 2 (1->4->5)
1) 如果 DFS 遍历 `1->2->3->4->5' 并到达目的地 '5' 它会将 '1' 返回到第 '4' 节点。
2) 现在第'4'节点记住返回值'1'。 (这意味着在4到5之间,有一个节点,包括目的地,不包括源4)。
2.1) 然后它返回'2'(1+1) 到'3'rd 节点。和'3'rd 节点记住值'2'。 (这意味着在第 3 个节点和目标(5)节点之间,有 2 个节点,在最短的路径中。包括目标,不包括源 3
3) 类似的调用将返回到“1”。
4) 然后是第'1'节点,调用第'4'节点并看到它之前被访问过,所以它取第'4'节点的记忆值'1'并将'2'返回到'1'。
【问题讨论】:
-
请edit您的帖子澄清问题:1.“用单位距离连接数字”是什么意思? 2.“实际答案:4”请说明为什么是4 3.请对测试数据进行硬编码,使代码更容易测试。
-
@c0der 我已经编辑了问题,你能检查一下吗?
-
谢谢。现在更清楚了。请说明原因实际答案:4
-
@c0der 我无法弄清楚为什么回答“4”,因为该图很大,有近 1000 个节点。我使用我在 SPOJ 中接受的 BFS 方法找到了实际答案。我已经编辑了我的问题来解释我的方法。请看一下。
标签: java graph depth-first-search breadth-first-search