首先声明的是这个问题的代码并不是本人所做,我只是抱着学习的态度,在此标记如下代码。
感谢算法原作者:新浪微博的“娱乐圈王一炜”,是他的帮助我才能顺利看懂这段代码,并从中学到许多知识。
问题描述(来自新浪微博的:”陈利人老师“):
“迷宫”题:从图左边入口处的2011进去,在迷宫里转悠,最后变成2012从右边出来。可以在迷宫里转圈,可以重复之前走过的路,但不能回退。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STARTVALUE 2011
#define ENDVALUE 2012
#define QUEUESIZE (1024*1024) //size of the queue for BFS
//四种状态:start指当前节点前进方向是start入口方向
// middle指当前节点所前进方向是middle中间口方向
// end指当前节点所前进方向是end出口方向
// unreachable状态只在计算下一扩展节点方向时使用用以说明由当前节点到下一节点是达不到的
typedef enum{START=0,MIDDLE=1,END=2,UNREACHABLE=3}State;
//五种操作:add +7,min -5 ,mul *3 ,div /2 ,other 只在初始节点是使用,用以记录当前节点是在什么操作下得到的
typedef enum{ADD=0,MIN=1,MUL=2,DIV=3,OTHER=4}Opera;
//节点信息:记录当前节点的父节点,节点当前值,节点是通过父节点经过什么操作得到,当前节点的前进方向,当前节点的派生后继
typedef struct Node{
int value,path;
Node * parent;
Node * child[4];
State state;
}*QuadTree;
//BFS树的根节点
QuadTree root;
//初始化新派生后继节点的函数
Node * NewNode(int v, Node* n,int p, State s){
Node *q = (Node *)malloc(sizeof(Node));
q->value = v;
q->parent = n;
q->path = p;
q->child[ADD] = q->child[MIN] = q->child[MUL] = q->child[DIV] = NULL;
q->state = s;
return q;
}
//存储一出现节点队列数据结构:节点指针,队列头,队列尾,队列大小
struct Queue{
Node ** data;
int size,header,tailer;
}NodeQueue;
//初始化祖先节点队列
void InitQueue(){
NodeQueue.data = (Node**)malloc(QUEUESIZE*sizeof(Node *));
NodeQueue.size = QUEUESIZE;
NodeQueue.header = NodeQueue.tailer = 0;
}
void EnQueue(Node * q){
if((NodeQueue.tailer+1)%NodeQueue.size == NodeQueue.header) {printf("Queue Overflow\n");return;}
NodeQueue.data[NodeQueue.tailer] = q;
NodeQueue.tailer = (NodeQueue.tailer+1)%NodeQueue.size;
}
Node* DeQueue(){
if(NodeQueue.header == NodeQueue.tailer) return NULL;
Node* temp = NodeQueue.data[NodeQueue.header];
NodeQueue.header = (NodeQueue.header+1)%NodeQueue.size;
return temp;
}
Node* PopStack(){ //queue also can be used as stack for outputing result
if(NodeQueue.header == NodeQueue.tailer) return NULL;
NodeQueue.tailer = (NodeQueue.tailer-1+NodeQueue.size)%NodeQueue.size;
return NodeQueue.data[NodeQueue.tailer];
}
int add(int temp){return temp+7;}
int minus(int temp){return temp-5;}
int mul(int temp){return (temp<<1)+temp;}
int div(int temp){return temp>>1;}
int (*fun[4])(int) ={add,minus,mul,div}; //function pointer
//three-dimensional matrice: according to [State], [Path], [Next operation] return [Next State]
State StateCompute[3][5][4]={
{ {UNREACHABLE,UNREACHABLE,UNREACHABLE,MIDDLE},
{UNREACHABLE,UNREACHABLE,UNREACHABLE,UNREACHABLE},
{UNREACHABLE,UNREACHABLE,UNREACHABLE,UNREACHABLE},
{MIDDLE,UNREACHABLE,UNREACHABLE,UNREACHABLE},
{MIDDLE,UNREACHABLE,UNREACHABLE,MIDDLE}
},
{ {UNREACHABLE,END,END,START},
{START,UNREACHABLE,END,START},
{START,END,UNREACHABLE,START},
{START,END,END,UNREACHABLE},
{UNREACHABLE,UNREACHABLE,UNREACHABLE,UNREACHABLE}
},
{ {UNREACHABLE,UNREACHABLE,UNREACHABLE,UNREACHABLE},
{UNREACHABLE,UNREACHABLE,MIDDLE,UNREACHABLE},
{UNREACHABLE,MIDDLE,UNREACHABLE,UNREACHABLE},
{UNREACHABLE,UNREACHABLE,UNREACHABLE,UNREACHABLE},
{UNREACHABLE,UNREACHABLE,UNREACHABLE,UNREACHABLE}
}
};
void OutputResult(Node* end){
char opera[] = "+7-5*3/2";
int i = 0;
while(end->parent!=NULL){
EnQueue(end);
end = end->parent;
}
while((end=PopStack())!=NULL)
printf("%d\t%d%c%c=%d\n",++i,end->parent->value,opera[2*end->path],opera[1+2*end->path],end->value);
}
#define BIT_SET(x,n) (x=x | (0x01<<n))
#define BIT_TEST(x,n) ((x & (0x01<<n))!=0)
#define MAXVALUE (65535)
unsigned char* ExistNode;
//此处说明一下为什么申请3*4*MAXVALUE*sizeof(CHAR)>>3的空间
//3 代表三种状态(即节点指向)START,MIDDLE,END
//4 代表四种操作 ADD,MINUR,MULTIPLY,DIV
//MAXVALUE 代表当前节点允许的最大状态值
//右移3位原因在于一个char型的存储空间为8位
//具体判重操作时,以上的3,4,MAXVALUE相当于三个权值,对应任意一个可能出现的状态节点我们采取如下操作
//(node->state*4*MAXVALUE>>3)+(node->path*MAXVALUE>>3)+(node->value>>3)使得每个状态节点被唯一的标记成一位
void InitPruning(){ // allocate memory for storing existing node, using bitmap algorithm
ExistNode = (unsigned char *) malloc(3*4*MAXVALUE*sizeof(char)>>3);
memset(ExistNode,NULL,3*4*MAXVALUE>>3);
}
bool Pruning(Node* node){
if(OTHER == node->path||(unsigned)node->value>MAXVALUE) return true;
if(BIT_TEST(ExistNode[(node->state*4*MAXVALUE>>3)+(node->path*MAXVALUE>>3)+(node->value>>3)],(node->value&0x07)))
return false;
BIT_SET(ExistNode[(node->state*4*MAXVALUE>>3)+(node->path*MAXVALUE>>3)+(node->value>>3)],(node->value&0x07)) ;
return true;
}
void Expand(Node * node){
int i;
for(i = 0; i < 4; i++ ){
if(UNREACHABLE ==StateCompute[node->state][node->path][i]) continue;
node->child[i] = NewNode(fun[i](node->value),node,i,StateCompute[node->state][node->path][i]);
if(Pruning(node->child[i])) EnQueue(node->child[i]);//位图
if(node->child[i]->value == ENDVALUE && node->child[i]->state == END){
NodeQueue.header = NodeQueue.tailer;
OutputResult(node->child[i]);
break;
}
}
}
void freeQuadTree(Node * tree){ //recursion is slow when tree is big
if(tree){
freeQuadTree(tree->child[0]);
freeQuadTree(tree->child[1]);
freeQuadTree(tree->child[2]);
freeQuadTree(tree->child[3]);
free(tree);
}
}
void freeMemory(){
if(NodeQueue.data){
free(NodeQueue.data);
NodeQueue.data = NULL;
}
if(ExistNode){
free(ExistNode);
ExistNode = NULL;
}
freeQuadTree(root);
}
int main(){
Node * q = root = NewNode(STARTVALUE,NULL,OTHER,START);
InitQueue();
InitPruning();
EnQueue(root);
while((q=DeQueue())!=NULL)
Expand(q);
printf("Completion!\n");
// freeMemory(); // free memory is slow
// getchar();
return 0;
}