推箱子 BFS解法 C语言实现

Sample 1

Input 1

4 4
 ..
 .B
GGB.
P...

Output 1

17
DDDWAAWWDSASSDDWA

Sample 2

Input 2

4 5
.. G
.BBBG
..C..
P. .G

Output 2

21
WDDDWDSAAAAWWDSASDWDD

Sample 3

Input 3

5 5
.....
.BGB.
GC CG
.BGB.
P....

Output 3

32
DDWASAWSDDDDWADWWWAASDWDSWAAAASD

Sample 4

Input 4

5 6
..
GBG..
.CBB..
..GB..
P. G.

Output 4

24
WWWDDSASAWDDDSDDWAWADSAA

Sample 5

Input 5

5 4
..
.G.
GGB
.BB.
P...

Output 5

72
DWSDDWAAWAWWDSDSWAASDSSDDWASAAWWDWDSAASSDWSDDWAWWAWASDDSSSAAWDWSSDDWASAW

Code

#include
#include

#define CharGround '.'
#define CharWall ' '
#define CharBox 'B'
#define CharGoal 'G'
#define CharBonG 'C'
#define CharPlay 'P'

typedef enum{False, True} Bool;

int n, m, s, b, pos2num[15][15];
char sce[15][15];
long long sta0, sta1;

struct
{
	int x, y;
}num2pos[127];
struct NumLst
{
	int numb[15], nump;
};

Bool charlegal(char c)
{
	if(c == CharGround) return True;
	if(c == CharWall) return True;
	if(c == CharBox) return True;
	if(c == CharGoal) return True;
	if(c == CharBonG) return True;
	if(c == CharPlay) return True;
	return False;
}

#define dxw + 1
#define dxs - 1
#define dxa
#define dxd

#define dyw
#define dys
#define dya - 1
#define dyd + 1

#define dxx
#define dyx

#define near(num, dir) pos2num[num2pos[num].x dx##dir][num2pos[num].y dy##dir]

struct NumLst sta2slt(long long sta)
{
	int i;
	struct NumLst res;
	res.nump = sta % s;
	for(i = b - 1; i >= 0; i--)
		sta /= s, res.numb[i] = sta % s;
	return res;
}

long long slt2sta(struct NumLst slt)
{
	int i;
	long long res = 0;
	for(i = 0; i < b; i++)
		res = (res + slt.numb[i]) * s;
	res += slt.nump;
	return res;
}

void pushinit()
{
	int i, j, sb, sg;
	struct NumLst slt0, slt1;
	s = sb = sg = 0;
	for(i = 0; i <= n + 1; i++)
		for(j = 0; j <= m + 1; j++)
			pos2num[i][j] = -1;
	for(i = 1; i <= n; i++)
		for(j = 1; j <= m; j++)
		{
			if(sce[i][j] != CharWall)
				num2pos[s].x = i, num2pos[s].y = j,
				pos2num[i][j] = s++;
			if(sce[i][j] == CharBox || sce[i][j] == CharBonG)
				slt0.numb[sb++] = pos2num[i][j];
			if(sce[i][j] == CharGoal || sce[i][j] == CharBonG)
				slt1.numb[sg++] = pos2num[i][j];
			if(sce[i][j] == CharPlay)
				slt0.nump = slt1.nump = pos2num[i][j];
		}
	if(sb != sg)
	{
		printf("Box not equal Goal\n");
		exit(0);
	}
	b = sb;
	sta0 = slt2sta(slt0);
	sta1 = slt2sta(slt1);
}

#define Chara 'A'
#define Chard 'D'
#define Chars 'S'
#define Charw 'W'
#define Charx 'X'

#define pushordw \
	while(i + 1 < b && slt.numb[i + 1] < num2) \
		slt.numb[i] = slt.numb[i + 1], i++;
#define pushords \
	while(i > 0 && slt.numb[i - 1] > num2) \
		slt.numb[i] = slt.numb[i - 1], i--;
#define pushorda
#define pushordd
#define pushordx

#define pushdir(sta, dir) \
({ \
	int i, j, num1, num2; \
	long long res; \
	struct NumLst slt; \
	slt = sta2slt(sta); \
	if(Char##dir != 'X') \
		num1 = near(slt.nump, dir); \
	else \
		num1 = sta0 % s; \
	if(num1 != -1) \
	{ \
		for(i = 0; i < b; i++) \
			if(slt.numb[i] == num1) \
				break; \
		if(i == b) \
		{ \
			slt.nump = num1; \
			res = slt2sta(slt); \
		} \
		else if(Char##dir != 'X') \
		{ \
			num2 = near(num1, dir); \
			if(num2 != -1) \
			{ \
				for(j = 0; j < b; j++) \
					if(num2 == slt.numb[j]) \
						break; \
				if(j == b) \
				{ \
					pushord##dir \
					slt.numb[i] = num2; \
					slt.nump = num1; \
					res = slt2sta(slt); \
				} \
				else \
					res = -1; \
			} \
			else \
				res = -1; \
		} \
		else \
			res = -1; \
	} \
	else \
		res = -1; \
	res; \
})

#define LenQue 5000000

char opr[LenQue];
int dst[LenQue], pre[LenQue], hasidx[LenQue], haslst[LenQue];
long long que[LenQue];

int hasfun(long long x)
{
	return x % 4999999;
}

void itq()
{
	int i;
	for(i = 0; i < LenQue; i++)
		hasidx[i] = -1;
}

Bool inq(long long sta)
{
	int i;
	for(i = hasidx[hasfun(sta)]; i != -1; i = haslst[i])
		if(que[i] == sta)
			return True;
	return False;
}

void enq(int rear)
{
	int key;
	key = hasfun(que[rear]);
	haslst[rear] = hasidx[key];
	hasidx[key] = rear;
}

#define pushque(dir) \
	stan = pushdir(que[head], dir); \
	if(stan != -1 && !inq(stan)) \
		que[rear] = stan, \
		dst[rear] = dst[head] + 1, \
		pre[rear] = head, \
		opr[rear] = Char##dir, \
		enq(rear), \
		rear++;

void output(int i)
{
	if(i == 0)
		return;
	output(pre[i]);
	printf("%c", opr[i]);
}

void push()
{
	int head, rear;
	long long stan;
	pushinit();
	head = rear = 0;
	que[rear] = sta0, dst[rear] = 0, rear++;
	itq(); enq(rear);
	while(head < rear)
	{
		if(que[head] / s == sta1 / s)
			break;
		pushque(w)
		pushque(s)
		pushque(a)
		pushque(d)
		//pushque(x)
		head++;
	}
	if(head == rear)
	{
		printf("No solution\n");
		return;
	}
	printf("Solved Step %d\n", dst[head]);
	output(head);
}

int main(int argc, char *argv[])
{
	FILE *fp;
	int i, j;
	char tmp;

	if(argc != 2)
	{
		printf("Parameter Error\n");
		return 0;
	}
	if((fp = fopen(argv[1], "r")) == NULL)
	{
		printf("Input Error\n");
		return 0;
	}

	fscanf(fp, "%d %d", &n, &m);
	for(i = 0; i <= n + 1; i++)
		for(j = 0; j <= m + 1; j++)
			sce[i][j] = ' ';

	tmp = fgetc(fp);
	for(i = n; i >= 1; i--)
	{
		tmp = fgetc(fp);
		for(j = 1; tmp != EOF && tmp != '\n'; j++)
		{
			if(!charlegal(tmp))
			{
				printf("Illegal Character\n");
				return 0;
			}
			sce[i][j] = tmp;
			tmp = fgetc(fp);
		}
	}
	fclose(fp);

	push();
	return 0;
}

2023.3.6

你可能感兴趣的:(c语言)