机试算法讲解: 第44题 深度优先搜索之素数环问题

/*
问题:在给定的1到n的数字中,将数字填入环中,使得环中任意2个相邻的数字和为素数。按字典序输出所有符合条件的解
回溯法:枚举每一个值,第一个放1时,尝试放入第二个数字,使其和1的和为素数,放入后再尝试第三个数,使其与第二个数的和为素数。直到所有数被全部放入环中,
       且最后一个数与1的和也是素数。
	   若发现当前位置无论放置任何之前未被使用的数均不能满足条件,回溯改变上一个数。
输入:n(1<n<17)
输入:
6
8
输出
case1
1 4 3 2 5 6
1 6 5 2 3 4
case2
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2

关键:
1 对于其余情况,首先要判断当前的数字是否在环中,若不在环中,先标记为已用,并尝试设置第num+1个数字在ans数组中,然后继续尝试放入下一个数字,最后再将该数字
  重新标记为未使用
2 注意剪枝的基本过程:初始化剪枝标记,初始化节点,放入循环中
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 17

//用于判定两个数的和是否为素数。
int prime[13] = {2,3,5,7,11,13,17,19,23,29,31,37,41};
//用于存放所有数的和
int ans[N];
bool mark[N];//剪枝标记

//判断一个数是否为素数
bool judge(int x)
{
	//判断一个数是否为素数
	for(int i = 0 ; i < 13 ; i++)
	{
		if(x==prime[i])
		{
			return true;
		}
	}
	return false;
}

//判断最后一个数和第一个数是之和是否为质数,若是,输出答案
bool check(int n)
{
	if(judge(ans[n] + ans[1])==false)
	{
		return false;
	}
	else
	{
		for(int i = 1 ; i <= n ; i++)
		{
			if(i!=1)
			{
				printf(" %d",ans[i]);
			}
			else
			{
				printf("%d",ans[i]);
			}
		}
		printf("\n");
		return true;
	}
}

//num:ans数组中已经存入的数字,n表示总共输入的数字个数
void DFS(int num,int n)
{
	//如果已经存在大于一个数字,就开始检查
	if(num > 1)
	{
		if(judge(ans[num] + ans[num-1])==false)
		{
			return;
		}
	}
	//如果所有数字全部确定完毕,需要检查第一个数和第n个数的和是否为质数
	if(num==n)
	{
		check(n);
		//检查结束之后就返回
		return;
	}
	//对第2个数到第n个数进行判定,递归判定
	for(int i = 2 ; i <= n ; i++)
	{
		//如果当前数未被尝试
		if(false==mark[i])
		{
			mark[i] = true;//标记该数已经被尝试
			ans[num+1] = i;//将新的数字加入到数组中
			DFS(num+1,n);//尝试新的数字
			mark[i] = false;//如果尝试失败,将当前数字重新设置为未被访问
		}
	}
}

int main(int argc,char* argv[])
{
	int n;
	int cnt = 0;//初始计数器设为0,计数符合要求的结果
	while(EOF!=scanf("%d",&n))
	{
		cnt++;
		printf("Case%d\n",cnt);
		//初始化,设定标记值
		for(int i = 0 ; i <= n ; i++)
		{
			mark[i] = false;
		}
		//设定初始节点,初始标记
		ans[1] = 1;
		mark[1] = true;
		DFS(1,n);
	}
	system("pause");
	getchar();
	return 0;
}

你可能感兴趣的:(深度优先搜索,素数环,机试算法)