2017-04-03 15 views
0
public class Solver { 

    public LinkedList<Sudoku> sudokus = new LinkedList<>(); 

    public Solver() { 
     Sudoku current = null; 
     int count = 1; 
     try (BufferedReader br = new BufferedReader(new FileReader(new File("p096_sudoku.txt")))) { 
      for (String line; (line = br.readLine()) != null;) { 
       if (line.contains("Grid")) { 
        current = new Sudoku(count); 
        sudokus.add(current); 
        count++; 
       } else { 
        current.addLine(line); 
       } 
      } 

     } catch (IOException ex) { 
      Logger.getLogger(Solver.class.getName()).log(Level.SEVERE, null, ex); 
     } 

    } 

    /* 
    For debugging purposes 
    */ 
    public void SolveFirstPrint() { 
     int count = 0; 
     for (Sudoku s : sudokus) { 
      if (count == 0) { 
       s.lines = solve(s.lines); 
       if (s.lines != null) { 
        for (int i = 0; i < 9; i++) { 
         for (int j = 0; j < 9; j++) { 

          System.out.print(s.lines[i][j] + " "); 
         } 
         System.out.print("\n"); 
        } 
       } 

       System.out.println(); 
      } 
      count++; 

     } 
    } 
    public void SolveFirst() { 
     int count = 0; 
     for (Sudoku s : sudokus) { 
      if (count == 0) { 
       s.lines = solve(s.lines); 
      } 
      count++; 
     } 
    } 




    public void SolveAllPrint() { 
     for (Sudoku s : sudokus) { 
      s.lines = solve(s.lines); 

     } 
     for (Sudoku s : sudokus) { 
      for (int i = 0; i < 9; i++) { 
       for (int j = 0; j < 9; j++) { 
        System.out.print(s.lines[i][j] + " "); 
       } 
       System.out.print("\n"); 
      } 
      System.out.println(); 
     } 
    } 
    public void SolveAll() { 

     for (Sudoku s : sudokus) { 
      s.lines = solve(s.lines); 

     } 
    } 

    public static boolean check(int[] numbers) { 
     int[][] key = new int[2][numbers.length]; 
     key[0] = numbers; 
     for (int i = 0; i < numbers.length; i++) { 
      key[1][i] = 0; 
     } 
     for (int i = 0; i < numbers.length; i++) { 
      if (numbers[i] > 0) { 
       key[1][numbers[i] - 1]++; 
      } 
     } 
     boolean keycheck = false; 
     for (int i = 0; i < numbers.length; i++) { 
      if (key[1][i] > 1) { 
       keycheck = true; 
       break; 
      } 
     } 
     if (keycheck == true) { 
      return false; 
     } else { 
      return true; 
     } 

    } 

    public static boolean checkY(int[][] numbers, int y) { 
     int[] key = new int[numbers[y].length]; 
     key = numbers[y]; 
     return check(key); 
    } 

    public static boolean checkX(int[][] numbers, int x) { 
     int[] key = new int[numbers.length]; 
     for (int i = 0; i < key.length; i++) { 
      key[i] = numbers[i][x]; 
     } 
     return check(key); 
    } 

    public static boolean checkAll(int[][] numbers) { 

     //Check Y lijnen 
     for (int i = 0; i < numbers.length; i++) { 
      if (!checkY(numbers, i)) { 
       return false; 
      } 
     } 
     //Check X lijnen 
     for (int i = 0; i < numbers.length; i++) { 
      if (!checkX(numbers, i)) { 
       return false; 
      } 
     } 

     // Check of alle boxes nog kloppen 
     if (!checkSquare(numbers, 0, 2, 0, 2)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 0, 2, 3, 5)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 0, 2, 6, 8)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 3, 5, 0, 2)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 3, 5, 3, 5)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 3, 5, 6, 8)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 6, 8, 0, 2)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 6, 8, 3, 5)) { 
      return false; 
     } 

     if (!checkSquare(numbers, 6, 8, 6, 8)) { 
      return false; 
     } 

     return true; 
    } 

    public static boolean checkSquare(int[][] numbers, int minX, int maxX, int minY, int maxY) { 

     Map<Integer, Integer> myMap = new HashMap<Integer, Integer>(); 
     for (int j = minY; j < maxY +1; j++) { 
      for (int i = minX; i < maxX +1; i++) { 
       if (numbers[j][i] != 0) { 
        // Als de hashmap al dezelfde key heeft in deze box 
        if (myMap.containsKey(numbers[j][i])) { 
         // Kan het huidige nummer niet ingevoerd worden, dus false. 
         return false; 
        } else { 
         // Voeg nummer toe 
         myMap.put(numbers[j][i], 1); 
        } 
       } 

      } 
     } 
     return true; 
    } 

    public static boolean isValid(int[][] numbers) { 
     // Controlleer of er wel een grid van 9x9 is 
     if (numbers.length != 9 || numbers[0].length != 9) { 
      return false; 
     } 
     return (checkAll(numbers)); 
    } 

    public static int[][] solve(int[][] numbers) { 
     int[] freeslot = getNext(numbers); 
     int f1 = freeslot[0]; 
     int f2 = freeslot[1]; 
     if (f1 == -1) { 
      return numbers; 
     } 
     numbers = recurseSolve(f1, f2, numbers); 
     return numbers; 
    } 

    public static int[][] recurseSolve(int yNR, int xNR, int[][] numbers) { 
     int[][] solved; 

     int[][] copy = new int[numbers.length][numbers[0].length]; 
     for (int y = 0; y < numbers.length; y++) { 
      for (int z = 0; z < numbers[0].length; z++) { 
       copy[y][z] = numbers[y][z]; 
      } 
     } 
     // Als t valid is doorgaan met next solven. 
     for (int i = 1; i < 10; i++) { 
      copy[yNR][xNR] = i; 
      boolean valide = isValid(copy); 
      if (valide) { 

       solved = solve(copy); 
       if (solved != null) { 
        return solved; 
       } 
      } 
     } 
     return null; 
    } 

    public static int[] getNext(int[][] numbers) { 
     int[] slot = {-1, -1}; 
     for (int i = 0; i < 9; i++) { 
      for (int j = 0; j < 9; j++) { 
       if (numbers[i][j] == 0) { 
        slot[0] = i; 
        slot[1] = j; 
        return slot; 
       } 
      } 
     } 
     return slot; 
    } 

    public int EulerSum() { 
     int total = 0; 
     for (Sudoku sudoku : sudokus) { 
      total += sudoku.TopLeftNrs(); 
     } 
     return total; 
    } 
} 

안녕 얘들 아!더 많은 입력을 위해 Java Sudoku 솔버를 더 빠르게 만들 수 있습니까?

위의 스도쿠 해결사를 만들었지 만 문제가 있습니다.

나는 아래의 성능 테스트했다 :

@Test 
public void speedTest(){ 
    solver = new Solver(); 
    long tStart = System.currentTimeMillis(); 

    solver.SolveFirst(); 
    long tEnd = System.currentTimeMillis(); 
    long tDelta = tEnd - tStart; 
    double elapsedSeconds = tDelta/1000.0; 
    System.out.println("1 Sudoku: " +elapsedSeconds); 
    solver = new Solver(); 
    long tStart2 = System.currentTimeMillis(); 
    solver.SolveAll(); 
    long tEnd2 = System.currentTimeMillis(); 
    long tDelta2 = tEnd2 - tStart2; 
    double elapsedSeconds2 = tDelta2/1000.0; 
    System.out.println("50 Sudokus:"+elapsedSeconds2); 
    } 


} 

을 그리고이 결과에서 얻을 :

있는 TestSuite :

1 스도쿠

InputTest : 0.014 초

50 스도쿠를 시도 0 : 7.314 초

1 스도쿠가 너무 빠르지 만 1 이상은 선형 성능 결과가 아닐 수 있습니까?

Int [] [] 이외의 다른 것을 사용해야합니까?

미리 감사드립니다.

+1

어쩌면 당신은 첫 번째 행운을 얻었을 것입니다. –

+0

@ SkottHunter가 맞다고 생각합니다. 역 추적을 사용하면 평가 된 잘못된 경로의 수가 잠재적으로 상당히 커질 수 있기 때문에 시간이 크게 달라질 수 있습니다. 그리고 보드를 항상 복사하는 경우 시간이 오래 걸리며 잘못된 동작을 취소하는 것이 더 빠릅니다. – maraca

+0

나는 그것을 똑똑한 사고로 들여다 보겠습니다. –

답변

0

나는 당신의 코드/질문을 한 눈에 보았을 뿐이지 만 당신의 해결사는 당신의 늪지대 표준 인 bruteforce Sudoku solver처럼 보입니다. 또한 입력 파일 (포함되지 않은)에서 Sudokus를 읽는 것 같습니다.

잠재적 인 이유는 다음과 같습니다. 모든 스도쿠가 동일한 것은 아니므로 해결하는 데 다른 시간이 걸립니다. 귀하의 코드가 입력 파일에서 일부 "마법"마법을 검사하기 때문에.

Sudoku에서 Bruteforce 해결자는 Sudoku를 해결하는 가장 효율적인 방법이 아닙니다. 사람들은 특정 요소를 입력하여 오랜 시간이 걸리게합니다.

어쨌든 내 추측입니다. 어떤 것들이 오랜 시간이 걸리는지 알아보기 위해 타이밍을 솔버 내부에 추가 할 수 있습니다.

또한 solveFirst 메서드는 불필요하게 퍼즐 모음 전체를 반복합니다. 첫 번째 문제를 해결하고 해결하기 만하는 이유는 무엇입니까?

+0

위반이있을 때까지 모든 숫자를 확인하기 때문에 짐작이 아닙니다. 백도어를 추적 할 수 있습니다. 가능한 한 많은 스도쿠를 생성하지 않으며 해결책인지 확인합니다. – maraca

+0

나는 분명히 내 남자를 역 추적했다. –

+1

"brute force"와 "backtracking"은 상호 배타적 인 것이 아닙니다. –