华容道求解:
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;
}