八皇后问题网页图形版本

这学期给学生讲《Web程序设计》,用JavaScript写了一个八皇后问题网页图形版本,采用了递归回溯算法,下面是网页截图: 

算法并不复杂,通过DOM控制HTML标签来显示图形,棋盘背景采用了表格,当然也可以采用JavaScript来生成,但并不会使网页代码精简很多。

之所以没有采用动态演示求解过程,是因为JavaScript无法实现类似线程的Sleep休眠功能来延时,更无法实现信号量、旗标等复杂的多线程功能,而JavaScript提供的setTimeout()和setInterval()方法实际上都是在浏览器中新开一个线程,并不会使脚本执行暂停,唯一的方法是为每一步骤单独编写函数,但那样做会使得程序异常晦涩难懂。当然,可能有人试图通过死循环来定时,但会导致程序无响应,而且也无法更新页面内容,显然这样做是一个非常糟糕的办法。

这是所有代码,可以直接保存成网页文件本地运行: 

  
  
  
  
  1. <html xmlns="http://www.w3.org/1999/xhtml"> 
  2. <head> 
  3.     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
  4.     <title>Eight Queens Puzzle(Recursive algorithm) - 八皇后问题(递归算法)</title> 
  5.     <style type="text/css"> 
  6.         body {  
  7.             background-color: #ffffc0;  
  8.         }  
  9.         p {  
  10.             text-align: center;  
  11.         }  
  12.         table {  
  13.             border-width: 8px;  
  14.             border-color: #604040;  
  15.             border-style: solid;  
  16.             background-color: #ffffff;  
  17.         }  
  18.         td {  
  19.             text-align: center;  
  20.             vertical-align: middle;  
  21.             width: 70px;  
  22.             height: 70px;  
  23.         }  
  24.         td.b {  
  25.             background-color: #000000;  
  26.         }  
  27.     </style> 
  28.     <script type="text/javascript"> 
  29.         var Q = new Array(8); //八皇后所在的列位置  
  30.  
  31.         // 判断第n个皇后与前面的n-1个皇后是否冲突  
  32.         function Clash(n) {  
  33.             var flag = false; //冲突标志  
  34.             var i = 0; //从第0行逐行判断  
  35.             while ((i < n) && !flag) {  
  36.                 flag = (Q[n] == Q[i]) || (Math.abs(Q[n] - Q[i]) == (n - i)); //在同一列或相同的对角线即为冲突  
  37.                 i++;  
  38.             }  
  39.             return flag;  
  40.         }  
  41.  
  42.         //搜索第n个皇后的位置  
  43.         function QSeek(n) {  
  44.             //判断是否已经回溯到了第一个皇后之前,即已经找到了所有解  
  45.             if (n >= 0) {  
  46.                 Q[n]++; //将该位置的皇后右移一个位置  
  47.                 if (Q[n] < 8) //当前行的皇后右移未超出范围  
  48.                 {  
  49.                     if (Clash(n)) //冲突则继续搜索当前行的皇后位置  
  50.                         return QSeek(n)  
  51.                     else //不冲突则当前行搜索完成  
  52.                         return true;  
  53.                 }  
  54.                 else //当前行无法安放,递归回溯  
  55.                 {  
  56.                     Q[n] = -1; //删除当前行的皇后  
  57.                     if (QSeek(n - 1)) //递归回溯  
  58.                         return QSeek(n) //在前一行搜索成功时,再搜索当前行  
  59.                     else  
  60.                         return false; //无解  
  61.                 }  
  62.             }  
  63.             else  
  64.                 return false; //无解  
  65.         }  
  66.  
  67.         var pic = "f0"; //默认的皇后图片字符串  
  68.  
  69.         //刷新皇后图片  
  70.         function showQueens() {  
  71.             //清除原有图像,即清除所有TD标记中的内容  
  72.             var tds = document.getElementsByTagName("TD");  
  73.             for (var i = 0; i < tds.length; i++)  
  74.                 tds[i].innerHTML = "";  
  75.             //绘制新图像  
  76.             for (var i = 0; i < 8; i++) {  
  77.                 eval("r" + i + "c" + Q[i] + ".innerHTML = \"<img src=\\\"" + pic + ".png\\\" />\";");  
  78.             }  
  79.         }  
  80.  
  81.         var count = 1; //记录解的个数  
  82.  
  83.         function Queens() {  
  84.             seekbtn.disabled = true; //禁用按钮  
  85.             seekpic.disabled = true; //禁用下拉列表  
  86.             if (count == 1) { //求第一组解时需搜索前7个皇后的位置  
  87.                 for (var i = 0; i < 7; i++)  
  88.                     QSeek(i);  
  89.             }  
  90.             if (QSeek(7)) {  
  91.                 showQueens();  
  92.                 seekbtn.value = "已经搜索到第" + count + "组解,准备搜索第" + ++count + "组解...";  
  93.                 seekpic.disabled = false; //恢复下拉列表  
  94.                 seekbtn.disabled = false; //恢复按钮  
  95.                 seekbtn.focus(); //设置焦点到按钮  
  96.             }  
  97.             else  
  98.                 seekbtn.value = "全部解已经搜索完成,共" + (count - 1) + "组!";  
  99.         }  
  100.     </script> 
  101. </head> 
  102. <body> 
  103.     <p> 
  104.         Eight Queens Puzzle (Recursive algorithm) - 八皇后问题(递归算法)<br /> 
  105.         Mengliao Software Studio(Baiyu) - 梦辽软件工作室(白宇)<br /> 
  106.         Copyright 2011, All right reserved. - 版权所有(C) 2011<br /> 
  107.         2011.04.04</p> 
  108.     <center> 
  109.         <table cellpadding="0" cellspacing="0"> 
  110.             <tr> 
  111.                 <td id="r0c0"></td> 
  112.                 <td class="b" id="r0c1"></td> 
  113.                 <td id="r0c2"></td> 
  114.                 <td class="b" id="r0c3"></td> 
  115.                 <td id="r0c4"></td> 
  116.                 <td class="b" id="r0c5"></td> 
  117.                 <td id="r0c6"></td> 
  118.                 <td class="b" id="r0c7"></td> 
  119.             </tr> 
  120.             <tr> 
  121.                 <td class="b" id="r1c0"></td> 
  122.                 <td id="r1c1"></td> 
  123.                 <td class="b" id="r1c2"></td> 
  124.                 <td id="r1c3"></td> 
  125.                 <td class="b" id="r1c4"></td> 
  126.                 <td id="r1c5"></td> 
  127.                 <td class="b" id="r1c6"></td> 
  128.                 <td id="r1c7"></td> 
  129.             </tr> 
  130.             <tr> 
  131.                 <td id="r2c0"></td> 
  132.                 <td class="b" id="r2c1"></td> 
  133.                 <td id="r2c2"></td> 
  134.                 <td class="b" id="r2c3"></td> 
  135.                 <td id="r2c4"></td> 
  136.                 <td class="b" id="r2c5"></td> 
  137.                 <td id="r2c6"></td> 
  138.                 <td class="b" id="r2c7"></td> 
  139.             </tr> 
  140.             <tr> 
  141.                 <td class="b" id="r3c0"></td> 
  142.                 <td id="r3c1"></td> 
  143.                 <td class="b" id="r3c2"></td> 
  144.                 <td id="r3c3"></td> 
  145.                 <td class="b" id="r3c4"></td> 
  146.                 <td id="r3c5"></td> 
  147.                 <td class="b" id="r3c6"></td> 
  148.                 <td id="r3c7"></td> 
  149.             </tr> 
  150.             <tr> 
  151.                 <td id="r4c0"></td> 
  152.                 <td class="b" id="r4c1"></td> 
  153.                 <td id="r4c2"></td> 
  154.                 <td class="b" id="r4c3"></td> 
  155.                 <td id="r4c4"></td> 
  156.                 <td class="b" id="r4c5"></td> 
  157.                 <td id="r4c6"></td> 
  158.                 <td class="b" id="r4c7"></td> 
  159.             </tr> 
  160.             <tr> 
  161.                 <td class="b" id="r5c0"></td> 
  162.                 <td id="r5c1"></td> 
  163.                 <td class="b" id="r5c2"></td> 
  164.                 <td id="r5c3"></td> 
  165.                 <td class="b" id="r5c4"></td> 
  166.                 <td id="r5c5"></td> 
  167.                 <td class="b" id="r5c6"></td> 
  168.                 <td id="r5c7"></td> 
  169.             </tr> 
  170.             <tr> 
  171.                 <td id="r6c0"></td> 
  172.                 <td class="b" id="r6c1"></td> 
  173.                 <td id="r6c2"></td> 
  174.                 <td class="b" id="r6c3"></td> 
  175.                 <td id="r6c4"></td> 
  176.                 <td class="b" id="r6c5"></td> 
  177.                 <td id="r6c6"></td> 
  178.                 <td class="b" id="r6c7"></td> 
  179.             </tr> 
  180.             <tr> 
  181.                 <td class="b" id="r7c0"></td> 
  182.                 <td id="r7c1"></td> 
  183.                 <td class="b" id="r7c2"></td> 
  184.                 <td id="r7c3"></td> 
  185.                 <td class="b" id="r7c4"></td> 
  186.                 <td id="r7c5"></td> 
  187.                 <td class="b" id="r7c6"></td> 
  188.                 <td id="r7c7"></td> 
  189.             </tr> 
  190.         </table> 
  191.         <br />皇后图片选择:  
  192.         <select id="seekpic" disabled="disabled" onchange="JavaScript: pic=this.value; showQueens();"> 
  193.             <option value="f0" selected="selected">图片一</option> 
  194.             <option value="f1">图片二</option> 
  195.             <option value="f2">图片三</option> 
  196.             <option value="f3">图片四</option> 
  197.             <option value="f4">图片五</option> 
  198.             <option value="f5">图片六</option> 
  199.             <option value="f6">图片七</option> 
  200.             <option value="f7">图片八</option> 
  201.             <option value="f8">图片九</option> 
  202.             <option value="f9">图片十</option> 
  203.         </select>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  
  204.         <input style="width: 300px; height: 25px" type="button" id="seekbtn" value="准备搜索第1组解..." onclick="Queens()" /> 
  205.     </center> 
  206. </body> 
  207. </html> 

标准的递归回溯算法,在求的每一组解后将末行的皇后向后移动一个位置继续求解,自然就是下一组解了,当所有解(共92组)求出后,将导致主函数返回false。

你可能感兴趣的:(JavaScript,职场,八皇后,休闲,递归回溯算法)