八数码问题

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <stdlib.h>

#define  M     3
#define  N     (M*M)
#define  SIZE  362880  //N!

typedef enum
{
	LEFT, RIGHT, UP, DOWN
}Towards;

typedef struct
{
	int  up, down, left, right;
}MatrixStatus;

typedef struct S
{
	int index, distance;
	struct S *next;
}QueueNode, *QueuePtr;

typedef struct
{
	QueuePtr front, rear;
}Queue, *LinkQueue;

void InitQueue(LinkQueue Q)
{
	Q->front = Q->rear = (QueuePtr)malloc(sizeof(QueueNode));
	Q->front->next = NULL;
}

void DestroyQueue(LinkQueue Q)
{
	while (Q->front)
	{
		Q->rear = Q->front->next;
		free(Q->front);
		Q->front = Q->rear;
	}
}

int  QueueEmpty(Queue Q)
{
	return Q.front == Q.rear;
}

void EnQueue(LinkQueue Q, int index, int distance)
{
	QueuePtr p  = (QueuePtr)malloc(sizeof(QueueNode));
	p->index    = index;
	p->distance = distance;
	p->next     = NULL;
	Q->rear->next = p;
	Q->rear       = p;
}

void DeQueue(LinkQueue Q, int *index, int *distance)
{
	QueuePtr p = Q->front->next;
	*index     = p->index;
	*distance  = p->distance;
	Q->front->next = p->next;
	if (Q->rear == p) Q->rear = Q->front;
	free(p);
}

static int fac[]  = { 1, 1, 2, 6, 24, 120, 720, 5040, 40320 };

/*
 * 康托展开
 */
int  GetIndex(char *str)
{
	int result = 0;
	for (int i = 0; i < N; i++)
	{
		int count = 0;
		for (int j = i + 1; j < N; j++)
		{
			count += str[i] > str[j];
		}
		result += count * fac[N - i - 1];
	}
	return result;
}

/*
 * 逆康托展开
 */
void UnCantor(char a[N], int x)
{
	int i, j, l, t;
	char h[N + M] = {0};

	for (i = 1; i <= N; i++)
	{
		t  = x / fac[N - i];
		x -= t * fac[N - i];

		for (j = 1, l = 0; l <= t; j++)
			if (!h[j])  l++;

		h[--j]   = 1;
		a[i - 1] = j - 1 + '0';
	}
}

void Swap(char *str, int ip, Towards flag)
{
	char tmp;

	switch (flag)
	{
	case LEFT:
		tmp = str[ip], str[ip] = str[ip - 1], str[ip - 1] = tmp;
		break;
	case RIGHT:
		tmp = str[ip], str[ip] = str[ip + 1], str[ip + 1] = tmp;
		break;
	case UP:
		tmp = str[ip], str[ip] = str[ip - M], str[ip - M] = tmp;
		break;
	case DOWN:
		tmp = str[ip], str[ip] = str[ip + M], str[ip + M] = tmp;
		break;
	}
}

int  FindZero(char *str)
{
	for (int i = 0; i < N; i++)
	{
		if ('0' == str[i])  return i;
	}
	return -1;
}

void InitArray(MatrixStatus *ans)
{
	char str[N];
	for (int i = 0; i < SIZE; i++)
	{
		UnCantor(str, i);
		int ip = FindZero(str);

		//LEFT
		if (ip % M)
		{
			Swap(str, ip, LEFT);
			ans[i].left = GetIndex(str);
			Swap(str, ip, LEFT);
		}
		else  ans[i].left = -1;

		//RIGHT
		if (M - 1 != ip % M)
		{
			Swap(str, ip, RIGHT);
			ans[i].right = GetIndex(str);
			Swap(str, ip, RIGHT);
		}
		else  ans[i].right = -1;

		//UP
		if (M <= ip)
		{
			Swap(str, ip, UP);
			ans[i].up = GetIndex(str);
			Swap(str, ip, UP);
		}
		else  ans[i].up = -1;

		//DOWN
		if (N - M > ip)
		{
			Swap(str, ip, DOWN);
			ans[i].down = GetIndex(str);
			Swap(str, ip, DOWN);
		}
		else  ans[i].down = -1;
	}
}

int  BFS(MatrixStatus *ans, int a, int b)
{
	Queue Q;
	int   tmp = a, index, distance, step = -1;
	char *flag = calloc(SIZE, sizeof(char));

	flag[tmp] = 1;
	InitQueue(&Q);
	EnQueue(&Q, tmp, 0);
	while (!QueueEmpty(Q))
	{
		DeQueue(&Q, &index, &distance);

		tmp = ans[index].left;
		if (-1 != tmp && !flag[tmp])
		{
			if (tmp == b)  break;
			EnQueue(&Q, tmp, distance + 1);
			flag[tmp] = 1;
		}

		tmp = ans[index].right;
		if (-1 != tmp && !flag[tmp])
		{
			if (tmp == b)  break;
			EnQueue(&Q, tmp, distance + 1);
			flag[tmp] = 1;
		}

		tmp = ans[index].up;
		if (-1 != tmp && !flag[tmp])
		{
			if (tmp == b)  break;
			EnQueue(&Q, tmp, distance + 1);
			flag[tmp] = 1;
		}

		tmp = ans[index].down;
		if (-1 != tmp && !flag[tmp])
		{
			if (tmp == b)  break;
			EnQueue(&Q, tmp, distance + 1);
			flag[tmp] = 1;
		}
	}
	if (!QueueEmpty(Q)) step = distance + 1;
	free(flag);  DestroyQueue(&Q);
	return step;
}

int main(int argc, char *argv[])
{
	int  a, b, T;
	char str[N + 1];
	MatrixStatus *ans = calloc(SIZE, sizeof(MatrixStatus));

	InitArray(ans);

	scanf("%d", &T);
	while (T--)
	{
		scanf("%s", str), scanf("%s", str + 3), scanf("%s", str + 6);
		a = GetIndex(str);

		scanf("%s", str), scanf("%s", str + 3), scanf("%s", str + 6);
		b = GetIndex(str);

		printf("%d\n", (a == b) ? 0 : BFS(ans, a, b));
	}
	free(ans);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值