华容道求解

来源:互联网 发布:消灭贫困 知乎 编辑:程序博客网 时间:2024/04/27 16:23


华容道求解:






void CHrdView::OnDirector()
{
    int x=0,toppos=2,nextpos=0,endpos=2,count,stepcount=1;
    int i,j,l;
    int canback=0,onlyone=0;
    char ordertemp[13];
    DWORD buffer[3100],checkbu,checkbu1,iStorOri;
    CString tempstr,addstr;
    char firststr[2][12];


/*  
    for( i=count-1; i >= 0; i--)
        for( j=0; j < i; j++)
            if(*(buffer+toppos+i) == *(buffer+toppos+j)){ *(buffer+toppos+i) = 0; break;}
*/
    if( iFill[1][3]+iFill[2][4] == 2 )
    {
        draw();
        return;
    }
    Fill2Str(iFill,firststr);
    str2long(firststr[0],buffer);
    iStorOri = *buffer;
    str2long(firststr[1],buffer+1);


    Conver(buffer[0],ordertemp);


    gonext(ordertemp, buffer+endpos, &count);


    for( i = count-2+endpos; i >= endpos; i -= 2)
    for( j=0; j < i; j++)
    {
            if(*(buffer+i) == *(buffer+j) || *(buffer+i+1) == *(buffer+j) ) {
                memmove (buffer+i,buffer+i+2,(endpos+count-i-2)<<2);
                count-=2;
                break;
            }
//              for( k = i+2; k < count + endpos; k++)
//                  *(buffer+k-2) = *(buffer+k); 


    }
    toppos = count + endpos;


    for( j=80;!canback && j>=0; j-- )
            for( i=endpos; i<toppos; i+=2)
                if( *(buffer+i) == StandDir[j] || *(buffer+i+1) == StandDir[j] ){
                    canback=1;
                    checkbu = *(buffer+i);
                    break;
                }


    while(!canback){
        stepcount++;
        nextpos = 0;
        for(l=endpos;l<toppos;l+=2){
//tempstr.Format ("count:%d,\nnextpos:%d,\nendpos:%d,\ntoppos: %d,\n%s",count,nextpos,endpos,toppos,(canback)?"找到":"没找到");
//AfxMessageBox(tempstr);
            Conver(buffer[l],ordertemp);
            gonext(ordertemp, buffer+toppos+nextpos, &count);


            for( i=count-2; i >= 0; i -= 2)
                for( j=0; j < toppos+i+nextpos; j+=2)
                    if(*(buffer+toppos+i+nextpos) == *(buffer+j) || *(buffer+toppos+i+nextpos+1) == *(buffer+j)) {
                        memmove (buffer+i+toppos+nextpos,buffer+i+toppos+nextpos+2,(count-i-2)<<2);
//                      for( k= i+toppos+nextpos+2; k < count+toppos+nextpos; k++)
//                          *(buffer+k-2) = *(buffer+k); 
                            count-=2;
                            break;
                        }
            nextpos += count;
            if( nextpos > 3085 ){ MessageBox("缓存不够,程序退出!");
            //DestroyWindow();
                return;}
        }
//
        for( j=80;!canback && j>=0; j--)
            for( i=toppos; i<toppos+nextpos; i+=2)
                if( *(buffer+i) == StandDir[j] || *(buffer+i+1) == StandDir[j]){
                    canback=1;
                    //x=i-((i-1)%2);
                    checkbu = buffer[i];
                    checkbu1 = buffer[i+1];
                    //Conver(buffer[x], cFillOrder);
                }


        if(!canback){
            memmove (buffer, buffer+endpos, (toppos+nextpos-endpos)<<2);
//          for( k = endpos; k < toppos+nextpos; k++)
//              *(buffer+k-endpos) = *(buffer+k); 
            endpos = toppos-endpos;
            toppos = nextpos+endpos;
        }
/*
        tempstr.Format ("current stepcount is %d,\nendpos is %d,\ntoppos is %d\n%s\n",stepcount,endpos,toppos,(canback)?"找到":"没找到");   
        for(i=endpos;i<toppos;i+=2){
            addstr.Format ("%d ",*(buffer+i));
            tempstr += addstr;
            if(!((i+1)%5)) {addstr.Format ("\n");tempstr += addstr;}
        }
        AfxMessageBox(_T(tempstr));
*/


    };


    if(stepcount>1){
            *buffer = checkbu;
            *(buffer+1) = checkbu1;
            endpos = 2;


            Conver(buffer[0],ordertemp);
            gonext(ordertemp, buffer+endpos, &count);


            for( i = count-2+endpos; i >= endpos; i -= 2)
            {
                for( j=0; j < i; j++)
                    if(*(buffer+i) == *(buffer+j) || *(buffer+i+1) == *(buffer+j) ) {
                        memmove (buffer+i,buffer+i+2,(endpos+count-i-2)<<2);
                        count-=2;
                        break;
                    }
        //                for( k = i+2; k < count + endpos; k++)
        //                    *(buffer+k-2) = *(buffer+k); 


            }
            toppos = count + endpos;
    }


    canback=0;
    while( !canback && stepcount>1)
    {


//  stepcount--;
//      if(onlyone)break;
        nextpos = 0;
        for(l=endpos;!canback && l<toppos;l+=2){
            Conver(buffer[l],ordertemp);
            gonext(ordertemp, buffer+toppos+nextpos, &count);


            for( i=count - 2; i >= 0; i -= 2)
                for( j=0; j < toppos+i+nextpos; j+=2)


                    if(*(buffer+toppos+i+nextpos) == *(buffer+j) || *(buffer+toppos+i+nextpos+1) == *(buffer+j)){
                        memmove (buffer+i+toppos+nextpos,buffer+i+toppos+nextpos+2,(count-i-2)<<2);
//                      for( k= i+toppos+nextpos+2; k < count+toppos+nextpos; k++)
//                          *(buffer+k-2) = *(buffer+k);
                        count-=2;
                        break;
                    }


            for(i=0; i<count; i+=2)
                if(iStorOri==*(buffer+toppos+i+nextpos) || iStorOri==*(buffer+toppos+i+nextpos+1))
                { canback=1;checkbu = buffer[l]; break;}
            nextpos += count;
            if( nextpos > 3085 ){ MessageBox("缓存不够,程序退出!");return;}
        }
        if(!canback){
            memmove (buffer, buffer+endpos, (toppos+nextpos-endpos)<<2);
    //     for( k = endpos ; k < toppos+nextpos; k++)
    //         *(buffer+k-endpos) = *(buffer+k); 
            endpos = toppos-endpos;
            toppos = nextpos+endpos;
        }
    }
        /*


        canback = 0;
        Conver(checkbu,ordertemp);
        gonext(ordertemp,raceback,&count);
        
        for(j=0;!canback && j<count;j+=2)
            for(i= endpos; i < toppos; i++)
                if( *(buffer+i) == raceback[j] ) {
//                  x=j;
                    checkbu = raceback[j]; 
                    canback = 1;
                    break;
                }
        Conver(iStorOri,ordertemp);
        gonext(ordertemp,raceback,&count);
        
        for(j=0;!canback && j<count;j+=2)
            for(i= endpos; i < toppos; i++)
                if( *(buffer+i) == raceback[j] ) {
//                  x=j;
                    checkbu = raceback[j]; 
                    canback = 1;
                    break;
                }
*/
//          if(!canback)AfxMessageBox("wrong for back");


//  Conver(strData.Mid ( iStepCount*10,10 ), cFillOrder);
/*
    if(!x){
        str2long(cFillOrder,&checkbu);
        for( i=0; i<toppos; i++)
            if( *(buffer+i) == checkbu){x=i;break;}
    }




        tempstr.Format ("back:current stepcount is %d,\nendpos is %d,\ntoppos is %d\n",stepcount,endpos,toppos);    
            for(i=endpos;i<toppos;i+=2){
                addstr.Format ("%d ",*(buffer+i));
                tempstr += addstr;
                if(!((i+1)%5)) {addstr.Format ("\n");tempstr += addstr;}
            }


            AfxMessageBox(_T(tempstr));
*/


    Conver(checkbu, cFillOrder);
    CreatePos(cFillOrder);
    iStepCount++;
    draw();
}


代码说明:
以上代码是我在2000年时完成的,采用的算法是广度搜索,但考虑到本问题的特点,对算法上做了改进,具体的方法是:先做一个程序,用广度搜索贪婪算法,找到最优解,然后将这条路径作为标准解存放到这个后写的程序中,从任何一种状态出发,则尝试着与这标准路径上的每一个状态做比较,如果匹配上了,则意味着最优解就获得了。因为这样改良后,性能得到了很大的提高。
后来,2002年时在学习opengl编程的时候,有幸看到里面的一个华容道例子,写的很精炼,也在此给出,它采用了贪婪法,位置信息通过hash表记录,和我采用的5进制编码有异曲同工之处:




unsigned
hash(Config config)
{
  int i, j, value;


  value = 0;
  for (i = 0; i < HEIGHT; i++) {
    for (j = 0; j < WIDTH; j++) {
      value = value + convert[config[i][j]];
      value *= 6;
    }
  }
  return (value);
}


int
solution(Config config)
{
  if (config[4][1] == 10 && config[4][2] == 10)
    return (1);
  return (0);
}
void
solidifyChain(struct puzzle *puzzle)
{
  int i;
  char buf[256];


  i = 0;
  while (puzzle->backptr) {
    i++;
    puzzle->backptr->solnptr = puzzle;
    puzzle = puzzle->backptr;
  }
  sprintf(buf, "%d moves to complete!", i);
  glutSetWindowTitle(buf);
}


int
addConfig(Config config, struct puzzle *back)
{
  unsigned hashvalue;
  struct puzzle *newpiece;
  struct puzzlelist *newlistentry;


  hashvalue = hash(config);


  newpiece = hashtable[hashvalue % HASHSIZE];
  while (newpiece != NULL) {
    if (newpiece->hashvalue == hashvalue) {
      int i, j;


      for (i = 0; i < WIDTH; i++) {
        for (j = 0; j < HEIGHT; j++) {
          if (convert[config[j][i]] !=
            convert[newpiece->pieces[j][i]])
            goto nomatch;
        }
      }
      return 0;
    }
  nomatch:
    newpiece = newpiece->next;
  }


  newpiece = (struct puzzle *) malloc(sizeof(struct puzzle));
  newpiece->next = hashtable[hashvalue % HASHSIZE];
  newpiece->hashvalue = hashvalue;
  memcpy(newpiece->pieces, config, HEIGHT * WIDTH);
  newpiece->backptr = back;
  newpiece->solnptr = NULL;
  hashtable[hashvalue % HASHSIZE] = newpiece;


  newlistentry = (struct puzzlelist *) malloc(sizeof(struct puzzlelist));
  newlistentry->puzzle = newpiece;
  newlistentry->next = NULL;


  if (lastentry) {
    lastentry->next = newlistentry;
  } else {
    puzzles = newlistentry;
  }
  lastentry = newlistentry;


  if (back == NULL) {
    startPuzzle = newpiece;
  }
  if (solution(config)) {
    solidifyChain(newpiece);
    return 1;
  }
  return 0;
}


int
generateNewConfigs(struct puzzle *puzzle)
{
  int i, j, k;
  Config pieces;
  Config newpieces;


  memcpy(pieces, puzzle->pieces, HEIGHT * WIDTH);
  for (i = 0; i < WIDTH; i++) {
    for (j = 0; j < HEIGHT; j++) {
      if (pieces[j][i] == 0) {
        for (k = 0; k < 4; k++) {
          if (canmove0(pieces, i, j, k, newpieces)) {
            if (addConfig(newpieces, puzzle))
              return 1;
          }
        }
      }
    }
  }
  return 0;
}


void
freeSolutions(void)
{
  struct puzzlelist *nextpuz;
  struct puzzle *puzzle, *next;
  int i;


  while (puzzles) {
    nextpuz = puzzles->next;
    free((char *) puzzles);
    puzzles = nextpuz;
  }
  lastentry = NULL;
  for (i = 0; i < HASHSIZE; i++) {
    puzzle = hashtable[i];
    hashtable[i] = NULL;
    while (puzzle) {
      next = puzzle->next;
      free((char *) puzzle);
      puzzle = next;
    }
  }
  startPuzzle = NULL;
}


int
continueSolving(void)
{
  struct puzzle *nextpuz;
  int i, j;
  int movedPiece;
  int movedir;
  int fromx, fromy;
  int tox, toy;


  if (startPuzzle == NULL)
    return 0;
  if (startPuzzle->solnptr == NULL) {
    freeSolutions();
    return 0;
  }
  nextpuz = startPuzzle->solnptr;
  movedPiece = 0;
  movedir = 0;
  for (i = 0; i < HEIGHT; i++) {
    for (j = 0; j < WIDTH; j++) {
      if (startPuzzle->pieces[i][j] != nextpuz->pieces[i][j]) {
        if (startPuzzle->pieces[i][j]) {
          movedPiece = startPuzzle->pieces[i][j];
          fromx = j;
          fromy = i;
          if (i < HEIGHT - 1 && nextpuz->pieces[i + 1][j] == movedPiece) {
            movedir = 3;
          } else {
            movedir = 2;
          }
          goto found_piece;
        } else {
          movedPiece = nextpuz->pieces[i][j];
          if (i < HEIGHT - 1 &&
            startPuzzle->pieces[i + 1][j] == movedPiece) {
            fromx = j;
            fromy = i + 1;
            movedir = 1;
          } else {
            fromx = j + 1;
            fromy = i;
            movedir = 0;
          }
          goto found_piece;
        }
      }
    }
  }
  glutSetWindowTitle("What!  No change?");
  freeSolutions();
  return 0;


found_piece:
  if (!movingPiece) {
    movingPiece = movedPiece;
    move_x = fromx;
    move_y = fromy;
  }
  move_x += xadds[movedir] * MOVE_SPEED;
  move_y += yadds[movedir] * MOVE_SPEED;


  tox = fromx + xadds[movedir];
  toy = fromy + yadds[movedir];


  if (move_x > tox - MOVE_SPEED / 2 && move_x < tox + MOVE_SPEED / 2 &&
    move_y > toy - MOVE_SPEED / 2 && move_y < toy + MOVE_SPEED / 2) {
    startPuzzle = nextpuz;
    movingPiece = 0;
  }
  memcpy(thePuzzle, startPuzzle->pieces, HEIGHT * WIDTH);
  changeState();
  return 1;
}


int
solvePuzzle(void)
{
  struct puzzlelist *nextpuz;
  char buf[256];
  int i;


  if (solution(thePuzzle)) {
    glutSetWindowTitle("Puzzle already solved!");
    return 0;
  }
  addConfig(thePuzzle, NULL);
  i = 0;


  while (puzzles) {
    i++;
    if (generateNewConfigs(puzzles->puzzle))
      break;
    nextpuz = puzzles->next;
    free((char *) puzzles);
    puzzles = nextpuz;
  }
  if (puzzles == NULL) {
    freeSolutions();
    sprintf(buf, "I can't solve it! (%d positions examined)", i);
    glutSetWindowTitle(buf);
    return 1;
  }
  return 1;
}



原创粉丝点击