欢迎访问:常州市武进区嘉泽中心小学网站 !今天是:
栏目列表
您现在的位置是:首页>>教师>>教师风采>>教师园地>>文章内容
近似于一笔画的问题
发布时间:2008-11-20   点击:   来源:本站原创   录入者:菜青虫

  近日,我班吴娜给我出了一个智力题:一个5*5的方阵(如图所示),要求只能横、竖走,且每个圈只能经过一次,问能不能一笔把所有的圈都画过来。
OOOOO
OOOOO
OOOOO
OOOOO
O OOO
  苦思良久,不得其解,便想编写一程序,让计算机遍历所有的分支,求出答案。可程序成败的关键是能把所有分支都遍历到。故把代码贴出,望网友指出其不对的地方。(程序运行后并没有找到一正确的分支,所以怀疑其题目是否有解,也或程序设计得不对)
  该程序启用了辅助线程进行计算,所以运行后不会出现对话框无响应的情况。

算法如下:  下载EXE文件
#define X(p) (p)%6
#define Y(p) ((p)/6-1)

BYTE g_data[42]= 
{// g_data 数组用以保存5*5的方阵信息,1为可走的圈,0为不可走,之所以上、下、右设0,是因为这样可以避免越界的判断,提高程序效率。
     0,0,0,0,0,0,
     1,1,1,1,1,0,
     1,1,1,1,1,0,
     1,1,1,1,1,0,
     1,1,1,1,1,0,
     1,0,1,1,1,0,
     0,0,0,0,0,0
};
int g_dd[4]={-1,-6,1,6};// g_dd 为当前圈的左、上、右、下四个方向增量
CByteArray g_wd;// g_wd 用来保存走过的节点
BYTE g_first,g_curr; //g_first为起点(这儿假设为左下角的圈,即g_data[30]);g_curr为当前走到的节点位置

int GetWay(int pos)//得到pos节点当前所走的方向。result:0-左;1-上;2-右;3-下
{
 int result;
 switch(g_wd.GetAt(pos+1)-g_wd.GetAt(pos))
 {
 case -1:
  result=0;
  break;
 case -6:
  result=1;
  break;
 case 1:
  result=2;
  break;
 case 6:
  result=3;
  break;
 }
 return result;
}

int cango(int pos)//pos节点是否还有其它方向可走
{
 for(int i=GetWay(pos)+1;i<4;i++)//从pos节点走过的下一方向开始计算
 {
  if(g_data[g_wd.GetAt(pos)+g_dd[i]])//下一方向可走则返回该方向值
   return i;
 }
 return 0;
}

CWinThread *g_pThread=NULL;//计算线程指针

UINT Think(LPVOID p)//遍历函数
{
 g_first=30;
    g_curr=30;
 g_wd.RemoveAll();
    g_wd.Add(g_first);
 int next;
 int cugo=0;

 ConedrawDlg *dlg=(ConedrawDlg *)p;
 do
 { 
  for(int i=cugo;i<4;i++)
  {   
   next=g_curr+g_dd[i];//next为i[0,3]方向上的下一节点
   if(g_data[next])//g_data[next]=1表示i方向上下一节点可走,0为不可走
   {
    g_curr=next;//更新当前节点值
    g_wd.Add(g_curr);//将当前节点添加进队列
    g_data[g_curr]=0;//当前节点设为不可走

    //更新结果窗口
    dlg->InvalidateRect(CRect(50,50,230,230),FALSE);
    dlg->UpdateWindow();
    break;
   }  
  }
  cugo=0;
  if(g_wd.GetSize()==24)//走过的节点数为24个
  {
   dlg->MessageBox("此题有解!");
   g_pThread=NULL;
   return 0;
  }
  if(i==4)//0-3四个方向都无路可走,则退回前面的某个节点
  {
   int l=(int)g_wd.GetUpperBound();//当前走过的最后一个节点
   int fir=l;
   do
   {
    g_data[g_wd.GetAt(l)]=1; //g_wd.GetAt(l)节点可走
    l--;
        
    if(l==0)//退到起点则表示此题无解
    {
     for(int m=fir;m>l;m--)//从队列中删除退回的一段节点
      g_wd.RemoveAt(m);
     dlg->Invalidate();
     dlg->UpdateWindow();
     dlg->MessageBox("此题无解!");
     dlg->GetDlgItem(IDC_BUTTON2)->SetWindowText("重新计算");
     g_pThread=NULL;
     return 0;
    }
    
    g_curr=g_wd.GetAt(l);
   }while(!(cugo=cango(l)));//前一节点是否还有其它方向可走

   for(int m=fir;m>l;m--)//从队列中删除退回的一段节点
    g_wd.RemoveAt(m);
  }  
 }while(g_wd.GetSize()<24);

 return 0;
}

附件:
    关闭窗口
    打印文档
    账号登录
    保持登录 忘记密码?
    账号与武进教师培训平台同步