手搓哈希表、列表、队列,只为了用C语言快速求解华容道游戏,我不是大佬,只是一个游戏算法爱好者

news2024/12/27 13:05:35

背景

多年前曾经写过C语言求解华容道,当时没有用到哈希表,导致整个查重搜索数组过大,每次求解都得花上数分钟的时间,如今时过境迁,对数据结构和算法有了更深的理解,所以得把这一块补上了。(其实就是最近想换工作,发现都喜欢算法大佬,所以写一个来敲一敲面试官的脑壳)

游戏

华容道挑战 7724游戏

方案

 把曹操格子用1表示,横将用2表示,竖将用3表示,小兵用4表示,空地用0表示,上图可以转化了代号

2244
3110
3110
3433
3433

把上术内容保存到文本文件problem.txt当中

编写源文件main.c,内容为

/*==============依赖库导入 start================*/
#include<stdio.h>				/* 标准输入输出库 */
#include<string.h>				/* 字符串处理库 */
#include<malloc.h>				/* 动态内存管理库 */
/*==============依赖库导入 end==================*/

/*================宏定义 start==================*/
/* 格子宏 */
#define SPACE '0'				/* 空格 */
#define BIG '1'					/* 大格 */
#define HORIZONTAL '2'			/* 横格 */
#define VERTICAL '3'			/* 竖格 */
#define SMALL '4'				/* 小格 */
/* 方向宏 */
#define UP 1					/* 上 */
#define DOWN 2					/* 下 */
#define LEFT 3					/* 左 */
#define RIGHT 4					/* 右 */
/* 哈希宏 */
#define PRIMER 31				/* 素数系数 */
#define MOD 10007				/* 素数哈希 */
/*================宏定义 end====================*/

/*===============数据结构 start=================*/
typedef struct LinkList { 		/* 链表 */
	char *str;					/* 字符串 */
	struct LinkList *next;		/* 下一个节点指针 */
} LinkList;

typedef struct HashSet {		/* 哈希集合 */
	LinkList *linkList[MOD];	/* 链表数组 */
} HashSet;

typedef struct Block {			/* 方块 */
	char type;					/* 类型 */
	int x;						/* 左上角横坐标 */
	int y;						/* 左上角纵坐标 */
	int w,h;					/* 格子宽高 */
	struct Block *next;			/* 下一个节点 */
} Block;

typedef struct Operation {		/* 操作 */
	int x,y;					/* 格子位置 */
	int direction;				/* 移动类型 */
} Operation;

typedef struct Node {			/* 节点 */
	char **arr;					/* 字符数组 */
	Operation *operation;		/* 上一步操作 */
	struct Node *previous;		/* 上一个节点 */
	struct Node *next;			/* 下一个节点 */
} Node;

typedef struct Queue {			/* 队列 */
	Node *head;					/* 队头 */
	Node *tail;					/* 队尾 */
	int count;					/* 数量 */
} Queue;
/*===============数据结构 end===================*/

/* 从文件读取题目 */
void readProblemFile(char **arr,char *filepath) {
	freopen(filepath,"r",stdin);
	int i,j;
	for(i=0; i<5; i++) {
		scanf("%s",arr[i]);
		printf("%s\n",arr[i]);
	}
	printf("\n");
}

/* 获取字符数组哈希码 */
int hashCode(char **arr,char value[]) {
	int res=0;
	int i,j,k=0;
	for(i=0; i<5; i++) {
		for(j=0; j<4; j++) {
			value[k]=arr[i][j];
			k++;
			res=res*PRIMER+arr[i][j]-'0';
			res%=MOD;
		}
	}
	return res;
}

/* 往哈希表中添加对象 */
int addObjectToHashSet(char **arr,HashSet *hashSet) {
	char value[21]= {'\0'};
	int code=hashCode(arr,value);
	LinkList *linkList=hashSet->linkList[code];
	while(linkList!=NULL) {
		if(strcmp(linkList->str,value)==0) {
			return 0;
		} else {
			linkList=linkList->next;
		}
	}
	LinkList *listHead=(LinkList*)malloc(sizeof(LinkList));
	listHead->str=(char*)malloc(sizeof(char)*21);
	strcpy(listHead->str,value);
	listHead->next=hashSet->linkList[code];
	hashSet->linkList[code]=listHead;
	return 1;
}

/* 释放哈希表 */
void freeHashSet(HashSet *hashSet) {
	int i;
	for(i=0; i<MOD; i++) {
		while(hashSet->linkList[i]!=NULL) {
			LinkList *linkList=hashSet->linkList[i];
			hashSet->linkList[i]=hashSet->linkList[i]->next;
			free(linkList);
		}
	}
	free(hashSet);
}

/* 入队 */
void enQueue(char **arr,int x,int y,int direction,Queue *queue) {
	int i;
	Node *node=(Node*)malloc(sizeof(Node));
	node->arr=(char**)malloc(sizeof(char*)*5);
	for(i=0; i<5; i++) {
		node->arr[i]=(char*)malloc(sizeof(char)*5);
		strcpy(node->arr[i],arr[i]);
	}
	if(x==-1||y==-1||direction==-1) {
		node->operation=NULL;
	} else {
		node->operation=(Operation*)malloc(sizeof(Operation));
		node->operation->x=x;
		node->operation->y=y;
		node->operation->direction=direction;
	}
	node->previous=NULL;
	node->next=NULL;

	if(queue->head==NULL) {
		queue->head=node;
		queue->tail=node;
		queue->count=0;
	} else {
		queue->tail->next=node;
		node->previous=queue->head;
		queue->tail=node;
	}
	queue->count++;
}

/* 出队 */
void deQueue(Queue *queue) {
	queue->head=queue->head->next;
	queue->count--;
}

/* 释放队列 */
void freeQueue(Queue *queue) {
	while(queue->head!=NULL) {
		Node* node=queue->head;
		queue->head=queue->head->next;

		if(node->operation!=NULL) {
			free(node->operation);
		}
		if(node->arr!=NULL) {
			int i;
			for(i=0; i<5; i++) {
				free(node->arr[i]);
			}
			free(node->arr);
		}
	}
	free(queue);
}

/* 生成格子链表 */
Block* getBlocks(char **arr) {
	int i,j,u,v;
	Block* blocks=NULL;
	char temp[5][4]= {0};
	for(i=0; i<5; i++) {
		strcpy(temp[i],arr[i]);
	}
	for(i=0; i<5; i++) {
		for(j=0; j<4; j++) {
			if(temp[i][j]==SPACE) {
				continue;
			}
			Block *block=(Block*)malloc(sizeof(Block));
			block->next=blocks;
			blocks=block;
			block->type=temp[i][j];
			block->x=i;
			block->y=j;
			switch(temp[i][j]) {
				case BIG:
					block->w=2;
					block->h=2;
					break;
				case HORIZONTAL:
					block->w=2;
					block->h=1;
					break;
				case VERTICAL:
					block->w=1;
					block->h=2;
					break;
				case SMALL:
					block->w=1;
					block->h=1;
					break;
			}
			for(u=i; u<i+block->h; u++) {
				for(v=j; v<j+block->w; v++) {
					temp[u][v]=SPACE;
				}
			}
		}
	}
	return blocks;
}

/* 释放格子链表 */
void freeBlocks(Block *blocks) {
	while(blocks->next!=NULL) {
		Block *block=blocks;
		blocks=blocks->next;
		free(block);
	}
}

/* 创建字符数组 */ 
char** createArray() {
	int i,j;
	char** res=(char**)malloc(sizeof(char*)*5);
	for(i=0; i<5; i++) {
		res[i]=(char*)malloc(sizeof(char)*5);
		for(j=0; j<4; j++) {
			res[i][j]='0';
		}
		res[i][4]='\0';
	}
	return res;
}

/* 释放字符数组 */
void freeArray(char **arr) {
	int i;
	for(i=0; i<5; i++) {
		free(arr[i]);
	}
	free(arr);
}

/* 方块转字符数组 */
void blocksToArray(Block *blocks,char **arr) {
	int i,j;
	while(blocks!=NULL) {
		Block *block=blocks;
		blocks=blocks->next;

		for(i=block->x; i<block->x+block->h; i++) {
			for(j=block->y; j<block->y+block->w; j++) {
				arr[i][j]=block->type;
			}
		}
	}
}

/* 打印所求结果 */
void displaySolution(Node *node) {
	if(node->operation==NULL) {
		return;
	} else {
		displaySolution(node->previous);
		int i;
		char directionName[][10]= {"","↑","↓","←","→"};
		printf("[%d,%d] %s\n",node->operation->x,node->operation->y,directionName[node->operation->direction]);
	}
}

/* 主函数 */
int main(int argc,char *argv[]) {
	char **array=(char**)malloc(sizeof(char*)*5);
	int i,j;
	for(i=0; i<5; i++) {
		array[i]=(char*)malloc(sizeof(char)*5);
		array[i][4]='\0';
	}

	if(argc==2) {
		readProblemFile(array,argv[1]);
	} else {
		strcpy(array[0],"3113\0");
		strcpy(array[1],"3113\0");
		strcpy(array[2],"3223\0");
		strcpy(array[3],"3443\0");
		strcpy(array[4],"4004\0");
	}

	HashSet hashSet;
	for(i=0; i<MOD; i++) {
		hashSet.linkList[i]=NULL;
	}
	Queue queue;
	queue.head=NULL;
	queue.tail=NULL;

	Node *result=NULL;

	addObjectToHashSet(array,&hashSet);

	enQueue(array,-1,-1,-1,&queue);
	free(array);

	while(queue.head!=NULL) {
		Node *node=queue.head;

		if(node->arr[3][1]==BIG && node->arr[4][2]==BIG) {
			result=node;
			break;
		}


		Block *blocks=getBlocks(node->arr);
		Block *blocksHead=blocks;


		while(blocksHead!=NULL) {
			Block *block=blocksHead;
			blocksHead=blocksHead->next;

			char **arr=NULL;

			switch(block->type) {
				case BIG:
					if(block->x>0 && node->arr[block->x-1][block->y]==SPACE && node->arr[block->x-1][block->y+1]==SPACE) {
						arr=createArray();
						block->x--;
						blocksToArray(blocks,arr);
						block->x++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,UP,&queue);
						}
					}

					if(block->x+block->h<5 && node->arr[block->x+block->h][block->y]==SPACE && node->arr[block->x+block->h][block->y+1]==SPACE) {
						arr=createArray();
						block->x++;
						blocksToArray(blocks,arr);
						block->x--;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,DOWN,&queue);
						}
					}

					if(block->y>0 && node->arr[block->x][block->y-1]==SPACE && node->arr[block->x+1][block->y-1]==SPACE) {
						arr=createArray();
						block->y--;
						blocksToArray(blocks,arr);
						block->y++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,LEFT,&queue);
						}
					}

					if(block->y+block->w<4 && node->arr[block->x][block->y+block->w]==SPACE && node->arr[block->x+1][block->y+block->w]==SPACE) {
						arr=createArray();
						block->y++;
						blocksToArray(blocks,arr);
						block->y--;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,RIGHT,&queue);
						}
					}

					break;
				case HORIZONTAL:
					if(block->x>0 && node->arr[block->x-1][block->y]==SPACE && node->arr[block->x-1][block->y+1]==SPACE) {
						arr=createArray();
						block->x--;
						blocksToArray(blocks,arr);
						block->x++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,UP,&queue);
						}
					}

					if(block->x+block->h<5 && node->arr[block->x+block->h][block->y]==SPACE && node->arr[block->x+block->h][block->y+1]==SPACE) {
						arr=createArray();
						block->x++;
						blocksToArray(blocks,arr);
						block->x--;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,DOWN,&queue);
						}
					}

					if(block->y>0 && node->arr[block->x][block->y-1]==SPACE) {
						arr=createArray();
						block->y--;
						blocksToArray(blocks,arr);
						block->y++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,LEFT,&queue);
						}
					}

					if(block->y+block->w<4 && node->arr[block->x][block->y+block->w]==SPACE) {
						arr=createArray();
						block->y++;
						blocksToArray(blocks,arr);
						block->y--;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,RIGHT,&queue);
						}
					}

					break;
				case VERTICAL:
					if(block->x>0 && node->arr[block->x-1][block->y]==SPACE) {
						arr=createArray();
						block->x--;
						blocksToArray(blocks,arr);
						block->x++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,UP,&queue);
						}
					}

					if(block->x+block->h<5 && node->arr[block->x+block->h][block->y]==SPACE) {
						arr=createArray();
						block->x++;
						blocksToArray(blocks,arr);
						block->x--;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,DOWN,&queue);
						}
					}

					if(block->y>0 && node->arr[block->x][block->y-1]==SPACE && node->arr[block->x+1][block->y-1]==SPACE) {
						arr=createArray();
						block->y--;
						blocksToArray(blocks,arr);
						block->y++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,LEFT,&queue);
						}
					}

					if(block->y+block->w<4 && node->arr[block->x][block->y+block->w]==SPACE && node->arr[block->x+1][block->y+block->w]==SPACE) {
						arr=createArray();
						block->y++;
						blocksToArray(blocks,arr);
						block->y--;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,RIGHT,&queue);
						}
					}
					break;
				case SMALL:

					if(block->x>0 && node->arr[block->x-1][block->y]==SPACE) {
						arr=createArray();
						block->x--;
						blocksToArray(blocks,arr);
						block->x++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,UP,&queue);
						}
					}

					if(block->x+block->h<5 && node->arr[block->x+block->h][block->y]==SPACE) {
						arr=createArray();
						block->x++;
						blocksToArray(blocks,arr);
						block->x--;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,DOWN,&queue);
						}
					}

					if(block->y>0 && node->arr[block->x][block->y-1]==SPACE) {
						arr=createArray();
						block->y--;
						blocksToArray(blocks,arr);
						block->y++;

						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,LEFT,&queue);
						}
					}

					if(block->y+block->w<4 && node->arr[block->x][block->y+block->w]==SPACE) {
						arr=createArray();
						block->y++;
						blocksToArray(blocks,arr);
						block->y--;
						if(addObjectToHashSet(arr,&hashSet)) {
							enQueue(arr,block->x,block->y,RIGHT,&queue);
						}
					}

					break;
			}
		}

		while(blocks!=NULL) {
			blocksHead=blocks;
			blocks=blocks->next;
			free(blocksHead);
		}
		
		deQueue(&queue);
	}

	if(result!=NULL) {
		printf("求解完成\n");
		displaySolution(result);
	} else {
		printf("此题无解\n");
	}
	
	freeHashSet(&hashSet);
	freeQueue(&queue); 

	return 0;
}

编译源文件main.c得到可执行程序main.exe,把main.exe和problem.txt放在同一个文件夹下。

使用cmd打开此目录,执行命令

main.exe problem.txt > 1.txt

稍后便可在目录下生成1.txt文件,里边保存的就是游戏的通关参考答案。

2244
3110
3110
3433
3433

求解完成
[3,3] ↑
[2,3] ↑
[3,2] →
[4,1] →
[3,1] ↓
[1,1] ↓
[0,2] ↓
[1,2] ←
[0,3] ←
[1,3] ↑
[3,3] ↑
[4,2] →
[0,2] ↓
[0,0] →
[1,0] ↑
[3,0] ↑
[4,1] ←
[2,1] ↓

思路

之前已经有博文进行了详细介绍,此处不再赘述。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1224378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE5制作场景时的小技巧和注意事项

UE5制作场景时的小技巧和注意事项 一、场景相关 1.1灯光 1.1.1构建完光照,发现场景都是黑的 可能是所有灯光是静态灯光,把skylight改为动态,如果改完之后还是黑色的,那就在构建一次,就应该没问题了 1.1.2场景中有多个动态光会造成阴影闪烁 需要将skylight变为固定 1…

CI/CD - jenkins

目录 一、部署 1、简介 2、部署 二、配置 三、实时触发 四、自动化构建docker镜像 五、通过ssh插件交付任务 六、添加jenkins节点 七、RBAC 八、pipeline 九、jenkins结合ansible参数化构建 1、安装ansible 2、新建gitlab项目 3、jenkins新建项目playbook 一、部…

linux进程之进程的优先级➕环境变量

文章目录 1.优先级的认识1.1优先级的介绍1.2初识优先级1.3ps指令1.4查看/修改进程的优先级1.5对优先级的认识1.6对进程的深一步理解 2.环境变量2.0环境变量相关的命令2.1环境变量的概念2.2常见/查看环境变量2.3环境变量的作用2.4修改环境变量1.将zombie可执行程序放到PATH现有的…

IOS object-c大屏图表 PNChart 折线图 曲线图

折线图是排列在工作表的列或行中的数据可以绘制到折线图中。折线图可以显示随时间&#xff08;根据常用比例设置&#xff09;而变化的连续数据&#xff0c;因此非常适用于显示在相等时间间隔下数据的趋势。在折线图中&#xff0c;类别数据沿水平轴均匀分布&#xff0c;所有值数…

​软考-高级-系统架构设计师教程(清华第2版)【第19章 大数据架构设计理论与实践 (P691~716)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第19章 大数据架构设计理论与实践 &#xff08;P691~716&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

AI Navigation导航系统_unity基础开发教程

AI Navigation导航系统 安装插件烘焙导航系统障碍物创建人物的AI导航动态障碍物 在unity编辑器中&#xff0c;有一个灰常好用的插件&#xff1a;Navigation。有了它1&#xff0c;你就可以实现人物自动走到你鼠标点击的位置&#xff0c;而且还会自动避开障碍物&#xff0c;下面就…

7、传统CV之高斯滤波

这一节在上一节均值滤波的基础上,再进阶一下,了解一下什么是高斯滤波。 首先,如上一节所说,均值滤波是利用一个窗口在图片上滑动,每次都计算窗口内能看到的像素的平均值,然后将平均值作为滤波的输出,从而可以起到平滑图像、去噪点的作用。 有没有发现,此时并没有特别…

SARAS-Net: Scale and Relation Aware Siamese Network for Change Detection

SARAS-Net&#xff1a;用于变化检测的尺度和关系感知的孪生网络 AAAI Chao-Peng Chen, Jun-Wei Hsieh, Ping-Yang Chen, Yi-Kuan Hsieh, Bor-Shiun Wang 2023 摘要&#xff1a;变化检测(CD)旨在找出不同时间两幅图像之间的差异&#xff0c;并输出变化图来表示该区域是否发生了…

C++17中std::variant的使用

可变参数模板类std::variant表示类型安全联合体(type-safe union)。std::variant的实例在任何给定时间要么保存其替代类型之一的值&#xff0c;要么在错误的情况下无值。 与union一样&#xff0c;如果std::variant保存某个对象类型T的值&#xff0c;则T的对象表示形式将直…

heatmap | cell cycle genes in Seurat

目的&#xff1a;使用bulk 数据&#xff0c;查看HeLa 双胸苷阻断法 细胞同步化 释放 [0, 3, 4.5, 6, 9, 10.5, 12, 15, 18, 19.5, 21, 22.5, 25.5, 30] 小时后 cell cycle 基因的表达情况。 1.结果 S phase G2M phase S G2M phase 不方便看&#xff0c;横过来看&#xff1a;…

Windows上搭建一个网站(基本生产环境)

前言 本博客记录的是Windows上一次网站搭建的过程&#xff0c;主要是在前端采用的是React&#xff0c;后端采用的是Flask&#xff0c;记录一下生产版本搭建流程和坑点&#xff0c;供有缘人一起进步&#xff0c;当然本博客还存在很多不足。 前端项目构建生产版本 以React为例…

【C++】容器string的常用成员函数接口

目录 string - C Reference 1 容量相关 1.1 size/length 1.2 capacity 1.3 resize 1.4 reserve 1.5 empty 2 运算符重载 2.1 operator 2.2 operator[] 2.3 operator&#xff08;非成员函数&#xff09; 2.4 operator 2.5 operator>> && operator<…

​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​

软考-高级-系统架构设计师教程&#xff08;清华第2版&#xff09;【第20章 系统架构设计师论文写作要点&#xff08;P717~728&#xff09;-思维导图】 课本里章节里所有蓝色字体的思维导图

人工智能-循环神经网络通过时间反向传播

到目前为止&#xff0c;我们已经反复提到像梯度爆炸或梯度消失&#xff0c; 以及需要对循环神经网络分离梯度。 例如&#xff0c;我们在序列上调用了detach函数。 为了能够快速构建模型并了解其工作原理&#xff0c; 上面所说的这些概念都没有得到充分的解释。 本节将更深入地探…

SpringSecurity6 | 自动配置(下)

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

CCF CSP认证 历年题目自练Day47

题目 试题编号&#xff1a; 201712-3 试题名称&#xff1a; Crontab 时间限制&#xff1a; 10.0s 内存限制&#xff1a; 256.0MB 样例输入 3 201711170032 201711222352 0 7 * * 1,3-5 get_up 30 23 * * Sat,Sun go_to_bed 15 12,18 * * * have_dinner 样例输出 201711170…

51.Sentinel微服务保护

目录 &#xff08;1&#xff09;初识Sentinel。 &#xff08;1.1&#xff09;雪崩问题及解决方案。 &#xff08;1.1.1&#xff09;雪崩问题。 &#xff08;1.1.2&#xff09;解决雪崩问题的四种方式。 &#xff08;1.1.3&#xff09;总结。 &#xff08;1.2&#xff09;…

【LeetCode刷题-滑动窗口】--345.反转字符串中的元音字母

345.反转字符串中的元音字母 class Solution {public String reverseVowels(String s) {int len s.length();if(len < 2){return s;}char[] charArray s.toCharArray();int left 0,right len - 1;while(true){while(left < len && checkVowels(charArray[lef…

C语言实现冒泡排序(超详细)

排序算法 - 冒泡排序 什么是冒泡排序&#xff1f;冒泡排序有啥用呢&#xff1f;冒泡排序的实现代码讲解冒泡排序的总结 什么是冒泡排序&#xff1f; 冒泡排序是一种简单的排序算法&#xff0c;它重复地遍历要排序的列表&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序…

【Linux】第十七站:进程创建与进程终止

文章目录 一、进程创建1.fork函数2.写时拷贝3.批量化创建多个进程 二、进程终止1.进程退出场景2.进程退出的方法&#xff08;1&#xff09;exit和return&#xff08;2&#xff09;_exit和exit 一、进程创建 1.fork函数 在linux中fork函数时非常重要的函数&#xff0c;它从已存…