八皇后问题的ABAP实现

*&---------------------------------------------------------------------*
*& Report  ZEIGHTQUEEN                                                 *
*& Date   :2007.09.04                                                  *
*&---------------------------------------------------------------------*
*八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世
*纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不
*能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多
*少种摆法。
*高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的
*解,后来有人用图论的方法解出92种结果。

*&---------------------------------------------------------------------*
REPORT  zeightqueen .

TYPES: BEGIN OF itab,
         lines TYPE n LENGTH 8,
       END OF itab.

DATA: gt_itab TYPE STANDARD TABLE OF itab WITH HEADER LINE.

DATA: g_line TYPE n LENGTH 1 VALUE '1',        "行
      g_row  TYPE n LENGTH 1 VALUE '1',        "列
      flag   TYPE c,
      g_num  TYPE i.

START-OF-SELECTION.
  DO.
    IF g_line = '9'.
      EXIT.
    ENDIF.
**初始化第一行
    PERFORM get_stru USING g_line
                CHANGING gt_itab.
    CLEAR: gt_itab[].
    APPEND gt_itab.
    g_line = g_line + 1.
**递归主体FORM
    PERFORM main_form USING g_line
                            g_row
                   CHANGING flag.
  ENDDO.
*&---------------------------------------------------------------------*
*&      Form  main_form
*&---------------------------------------------------------------------*
      text
*----------------------------------------------------------------------*
     -->P_G_Y  text
     <--P_FLAG  text
*----------------------------------------------------------------------*
FORM main_form  USING    p_line
                         p_row
                CHANGING p_flag.
  DATA: l_line TYPE i,
        l_row  TYPE i,
        l_flag TYPE c.
**从当前行的下一行的第一个位置开始CHECK
  l_line = 1.
  l_row  = p_row + 1.

  DO.
**CHECK到本行最后一个位置
    IF l_line = '9'.
      p_flag = l_flag.
      EXIT.
    ENDIF.
**CHECK到最后一行
    IF l_row = '9'.
      p_flag = 'S'.
      EXIT.
    ENDIF.
**CHECK FROM
    PERFORM check_line_row USING l_line l_row
                        CHANGING l_flag.
    IF l_flag = 'S'.
**此位置可用
      PERFORM get_stru USING l_line
                    CHANGING gt_itab.
      APPEND gt_itab.
      IF l_row = '8'.
**如果已经CHECK满8行,则输出
        PERFORM write_itab.
        l_line = l_line + 1.
        DELETE gt_itab INDEX l_row.
      ELSE.
**未满8行,继续CHECK下一行
        PERFORM main_form USING l_line
                                l_row
                       CHANGING l_flag.
        IF l_flag = 'F'.
          l_line = l_line + 1.
          DELETE gt_itab INDEX l_row.
        ELSE.
          l_line = l_line + 1.
          DELETE gt_itab INDEX l_row.
        ENDIF.
      ENDIF.
**此位置不可用,CHECK下一位置
    ELSE.
      l_flag = 'F'.
      l_line = l_line + 1.
    ENDIF.
  ENDDO.

ENDFORM.                    " main_form
*&---------------------------------------------------------------------*
*&      Form  check_line_row
*&---------------------------------------------------------------------*
      text
*----------------------------------------------------------------------*
     -->P_L_LINE  text
     -->P_L_ROW  text
     <--P_L_FLAG  text
*----------------------------------------------------------------------*
FORM check_line_row  USING    p_line
                              p_row
                     CHANGING p_flag.

  DATA: l_row      TYPE i,
        l_line     TYPE i,
        l_before_p TYPE i,
        l_after_p  TYPE i.

  l_row = p_row.

  DO.
    l_row = l_row - 1.
    IF l_row = '0'.
      EXIT.
    ENDIF.
    READ TABLE gt_itab INDEX l_row.
    IF sy-subrc = 0.
**从最近的一行,一行一行向上读取
      PERFORM get_line USING gt_itab
                    CHANGING l_line.
      l_before_p = l_line + ( p_row - l_row ).  "在P_LINE P_ROW之前
      l_after_p  = l_line - ( p_row - l_row ).  "在P_LINE P_ROW之后
**在同一直线上则P_FLAG = 'F'否则为'S'
      IF p_line = l_line.
        p_flag = 'F'.
        EXIT.
      ELSEIF p_line = l_before_p.
        p_flag = 'F'.
        EXIT.
      ELSEIF p_line = l_after_p.
        p_flag = 'F'.
        EXIT.
      ELSE.
        p_flag = 'S'.
      ENDIF.
    ENDIF.
  ENDDO.

ENDFORM.                    " check_line_row
*&---------------------------------------------------------------------*
*&      Form  get_line
*&---------------------------------------------------------------------*
      text
*----------------------------------------------------------------------*
     -->P_GT_ITAB  text
     <--P_L_LINE  text
*----------------------------------------------------------------------*
FORM get_line  USING    p_itab
               CHANGING p_line.
**从一行只有0和1组成的字符串中获取1的位置
**例如:'01000000',此时 P_LINE = '2'
  CASE p_itab.
    WHEN '10000000'.
      p_line = 1.
    WHEN '01000000'.
      p_line = 2.
    WHEN '00100000'.
      p_line = 3.
    WHEN '00010000'.
      p_line = 4.
    WHEN '00001000'.
      p_line = 5.
    WHEN '00000100'.
      p_line = 6.
    WHEN '00000010'.
      p_line = 7.
    WHEN '00000001'.
      p_line = 8.
    WHEN OTHERS.
**ERROR
  ENDCASE.

ENDFORM.                    " get_line
*&---------------------------------------------------------------------*
*&      Form  get_stru
*&---------------------------------------------------------------------*
      text
*----------------------------------------------------------------------*
     -->P_L_LINE  text
     <--P_GT_ITAB  text
*----------------------------------------------------------------------*
FORM get_stru  USING    p_line
               CHANGING p_itab.
**根据P_LINE的数值生成一条由1和0组织的字符串
**例如:P_LINE = '2'则P_ITAB = '01000000'
  CASE p_line.
    WHEN '1'.
      p_itab = '10000000'.
    WHEN '2'.
      p_itab = '01000000'.
    WHEN '3'.
      p_itab = '00100000'.
    WHEN '4'.
      p_itab = '00010000'.
    WHEN '5'.
      p_itab = '00001000'.
    WHEN '6'.
      p_itab = '00000100'.
    WHEN '7'.
      p_itab = '00000010'.
    WHEN '8'.
      p_itab = '00000001'.
    WHEN OTHERS.
**ERROR
  ENDCASE.

ENDFORM.                    " get_stru
*&---------------------------------------------------------------------*
*&      Form  write_itab
*&---------------------------------------------------------------------*
      text
*----------------------------------------------------------------------*
-->  p1        text
<--  p2        text
*----------------------------------------------------------------------*
FORM write_itab .
  DATA: l_num  TYPE i,
        l_box1 TYPE c,
        l_box2 TYPE c,
        l_box3 TYPE c,
        l_box4 TYPE c,
        l_box5 TYPE c,
        l_box6 TYPE c,
        l_box7 TYPE c,
        l_box8 TYPE c.

  g_num = g_num + 1.
  WRITE / g_num.

  LOOP AT gt_itab.
    IF gt_itab+0(1) = '0'.
      l_box1 = ''.
    ELSEIF gt_itab+0(1) = '1'.
      l_box1 = 'X'.
    ENDIF.
    IF gt_itab+1(1) = '0'.
      l_box2 = ''.
    ELSEIF gt_itab+1(1) = '1'.
      l_box2 = 'X'.
    ENDIF.
    IF gt_itab+2(1) = '0'.
      l_box3 = ''.
    ELSEIF gt_itab+2(1) = '1'.
      l_box3 = 'X'.
    ENDIF.
    IF gt_itab+3(1) = '0'.
      l_box4 = ''.
    ELSEIF gt_itab+3(1) = '1'.
      l_box4 = 'X'.
    ENDIF.
    IF gt_itab+4(1) = '0'.
      l_box5 = ''.
    ELSEIF gt_itab+4(1) = '1'.
      l_box5 = 'X'.
    ENDIF.
    IF gt_itab+5(1) = '0'.
      l_box6 = ''.
    ELSEIF gt_itab+5(1) = '1'.
      l_box6 = 'X'.
    ENDIF.
    IF gt_itab+6(1) = '0'.
      l_box7 = ''.
    ELSEIF gt_itab+6(1) = '1'.
      l_box7 = 'X'.
    ENDIF.
    IF gt_itab+7(1) = '0'.
      l_box8 = ''.
    ELSEIF gt_itab+7(1) = '1'.
      l_box8 = 'X'.
    ENDIF.
    WRITE: / l_box1 AS CHECKBOX INPUT OFF,
             l_box2 AS CHECKBOX INPUT OFF,
             l_box3 AS CHECKBOX INPUT OFF,
             l_box4 AS CHECKBOX INPUT OFF,
             l_box5 AS CHECKBOX INPUT OFF,
             l_box6 AS CHECKBOX INPUT OFF,
             l_box7 AS CHECKBOX INPUT OFF,
             l_box8 AS CHECKBOX INPUT OFF.
  ENDLOOP.

ENDFORM.                    " write_itab

posted @ 2011-08-20 17:14  VerySky  阅读(380)  评论(0编辑  收藏  举报