回溯算法2——填字游戏

为君一笑 提交于 2020-02-03 18:05:47

在3x3的方格中填入数字1~N(N>0)中的某9个数字,每个方格填1个整数,使相邻的两个方格中的整数之和为质数。求满足以上要求的各种数字填法。
【分析】
利用试探法找到问题的解,即从第一一个方格开始, 为当前方格寻找一个合理的整数填入,并在当前位置正确填入后,为下一方格寻找可填入的合理整数。如果不能为当前方格找到一个合理的可填整数,就要回退到前一方格,调整前一方格的填入数。当第9个方格也填入合理的整数后,就找到了一个解,将该解输出,并调整第9个填入的整数,继续寻找下一个解。为了检查当前方格填入整数的合理性,引入二维数组checkMatrix 存放需要合理性检查的相邻方格的序号。

为了找到一个满足要求的9个数的填法,按照某种顺序(如从小到大)每次在当前位置填入一个整数,然后检查当前填入的整数是否能够满足要求。在满足要求的情况下,继续用同样的方法为下一方格填入整数。 如果最近填入的整数不能满足要求,就改变填入的整数。 如果对当前方格试尽所有可能的整数,都不能满足要求,就得回退到前一方格 (回溯),并调整该方格填入的整数。如此重复扩展、检查、调整,直到找到一个满足问题要求的解, 将解输出。

code:

#include<stdio.h>
#define N 12
int b[N + 1];
int a[10];/*存放方格填入的整数*/
int total = 0;/*共有多少种填法*/
int checkmatrix[][3] = { { -1 },{ 0,-1 },{ 1,-1 },
{ 0,-1 },{ 1,3,-1 },{ 2,4,-1 },
{ 3,-1 },{ 4,6,-1 },{ 5,7,-1 } };
void write(int a[])
/*输出方格中的数字*/
{
	int i, j;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 3; j++)
			printf("%3d", a[3 * i + j]);
		printf("\n");
	}
}
int isprime(int m)
/*判断m是否是质数*/
{
	int i;
	int primes[] = { 2,3,5,7,11,17,19,23,29,-1 };
	if (m == 1 || m % 2 == 0)
		return 0;
	for (i = 0; primes[i]>0; i++)
		if (m == primes[i])
			return 1;
	for (i = 3; i*i <= m;)
	{
		if (m%i == 0)
			return 0;
		i += 2;
	}
	return 1;
}
int selectnum(int start)
/*从start开始选择没有使用过的数字*/
{
	int j;
	for (j = start; j <= N; j++)
		if (b[j])
			return j;
	return 0;
}
int check(int pos)
/*检查填入的pos位置是否合理*/
{
	int i, j;
	if (pos < 0)
		return 0;
	/*判断相邻的两个数是否是质数*/
	for (i = 0; (j = checkmatrix[pos][i]) >= 0; i++)
		if (!isprime(a[pos] + a[j]))
			return 0;
	return 1;
}
int extend(int pos)
/*为下一个方格找一个还没有使用过的数字*/
{
	a[++pos] = selectnum(1);
	b[a[pos]] = 0;
	return pos;
}
int change(int pos)
/*调整填入的数,为当前方格寻找下一个还没有用到的数*/
{
	int j;
	/*如果所有数都被使用,则回溯*/
	while (pos >= 0 && (j = selectnum(a[pos] + 1)) == 0)
		b[a[pos--]] = 1;
	if (pos < 0)
		return -1;
	b[a[pos]] = 1;
	a[pos] = j;
	b[j] = 0;
	return pos;
}
void find()
/*查找*/
{
	int ok = 0, pos = 0;
	a[pos] = 1;
	b[a[pos]] = 0;
	do
	{
		if (ok)
			if (pos == 8)
			{
				total++;
				printf("第%d种填法\n", total);
				write(a);
				pos = change(pos);/*调整*/
			}
			else
				pos = extend(pos);/*扩展*/
		else
			pos = change(pos);/*调整*/
		ok = check(pos);/*检查*/
	} while (pos >= 0);
}
void main()
{
	int i;
	for (i = 1; i <= N; i++)
		b[i] = 1;
	find();
	printf("共有%d种填法\n", total);

	getchar();
}

结果:


 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!