题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1016
方法:建立好状态树,状态树中的每一个节点有4个变量,即
1,当前状态为构造最终目标状态使用了什么数字的数组,后文称usedNums。
2,当前状态为构造最终目标状态还可以使用的数字的数组,后文称avaliableNums。
3,当前状态为构造最终目标状态已经构造了多大的长度,也就是该状态节点在树中的层数,后文称layer。
4,目标状态的长度。
每一个状态节点使用当前所在层数-1作为下标,取出已经构造好了的usedNums的最后一个数字x。然后枚举当前avaliableNums的数字y,看能不能和x相加得到素数,如果能,则其子状态节点的usedNums为其usedNums加上y,avaliableNums为其avaliableNums去掉y.然后从其子节点开始深搜。
如果当前状态节点所有的avaliableNums都枚举完毕都不能再找到能和x相加得到素数的y,搜索就此停止,该搜索路径不能达到目标状态。
否则一直搜索到目标状态所在那一层,再判断最后一个数和第一个数相加能不能得到素数。能就说明是个满足要求的素数环,输出,否则收索失败,直接返回。
感想:再构造子状态节点的时候,可以把当前状态的usedNums和avaliableNums先统一地复制给各个子状态节点,然后在搜索的时候分别更新各自的usedNums和avaliableNums。这样效率高点,而不是在从每个子节点开始深搜的时候,分别为每个子节点复制下当前的usedNums和avaliableNums,然后再跟新。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> using namespace std; int n; bool isPrime[] = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0}; int g_source[20] = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} ; int g_target[20] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} ; void DFSSearch(int source[20], int layerNo, int target[20]) { if(layerNo == n-1) { if(isPrime[target[layerNo]+1]) { for(int i = 0;i<n;i++) { printf("%d",target[i]); if(i<n-1) printf(" "); else printf("\n"); } } return; } else { int t_source[20],t_target[20]; for(int i = 0;i<n;i++) { t_source[i]=source[i]; t_target[i]=target[i]; } for(int i = 0;i<n;i++) { if(source[i]!=0) { if(isPrime[source[i]+target[layerNo]]) { t_source[i]=0; t_target[layerNo+1] = source[i]; DFSSearch(t_source,layerNo+1,t_target); t_source[i]=source[i]; } } } } } int main() { int i=1; while(scanf("%d",&n)!=EOF) { printf("Case %d:\n",i); DFSSearch(g_source,0,g_target); printf("\n"); i++; } return 0; }