许爷某天ak太多了心烦,想带领他的小跟班们做游戏 。
游戏内容如下:
当许爷喊出一个数字n时,便有n个小伙伴,身上带着1到n的数字,手牵手拉成一个环。当环里的每个人相邻两人身上数字之和都为素数时,便找到了一个环。当找出所有的环时,游戏便结束。
Note: 每个环的第一个数字必须是1
Input
n (0 < n < 20).
Output
输出格式如下方输出样例所示。
每行一串数字表示一种环中数字的排列顺序。数字的顺序必须满足:从1开始,顺时针或逆时针。按字典序输出所有解决方案。您将编写一个完成上述过程,帮助大家顺利完成游戏的程序。
别忘了在每组方案后面输出一个空行。
Sample Input
6
8
Sample Output
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
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
这道题看到之后,是道全排列的题目,内心窃喜,没有什么函数permutation 搞不定的,(心想什么手写全排列DFS,上我 permutation 函数),很快写了一发,交上去,直接超时,一看20的数据量很大,肯定会超时的,本题需要剪枝,挑选满足条件的组合,不然就会超时。于是手写DFS全排列,应该是在填充数组的时候就使数组一个环满足素数条件,不应该是全排列完再去判断是否满足素数条件(学到了,完美的剪枝策略),这很浪费时间:
代码:
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1000;
#include<iostream>
typedef long long ll;
int a[maxn];
bool vis[maxn];
int Prime[maxn];
int cnt;
int n;
int used[maxn];
void fun()
{
cnt = 0;
memset(vis,true,sizeof(vis));
vis[0] = vis[1] = false;
vis[2] = true;
for(int i = 2 ; i<=maxn; i++)
{
if(vis[i])
{
Prime[cnt++] = i;
for(int j = i+i ; j<=maxn; j+=i)
{
vis[j] = false;
}
}
}
}
void dfs(int x)
{
if(x==n+1&&vis[a[1]+a[n]]&&a[1]==1)
{
int g=0;
int k=0;
for(int i=1;i<=n-1;i++)
{
if(vis[a[i]+a[i+1]])
k++;
}
if(k==n-1)
{
for(int i=1;i<=n;i++)
{
if(g)
cout<<' ';
g=1;
cout<<a[i];
}
cout<<endl;
}
return ;
}
else
for(int i=2;i<=n;i++)
{
if(!used[i])
{
if(vis[i+a[x-1]])
{
a[x]=i;
used[i]=1;
dfs(x+1);
used[i]=0;
}
}
}
return ;
}
int main()
{
fun();
int kase=0;
int i=0;
while(cin>>n)
{
memset(used,0,sizeof(used));
printf("Case %d:\n",++kase);
if(n==1)
{
cout<<"1"<<endl;
continue;
}
a[1]=1;
dfs(2);
cout<<endl;
}
return 0;
}
DFS 剪枝判断 学到了 。