A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.
Note: the number of first circle should always be 1.
Input
n (0 < n < 20).
Output
The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.
You are to write a program that completes above process.
Print a blank line after each case.
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
思路:利用dfs和回溯,给每个数设定一个标记位,判断当前数能否加入该位置,最后还要判断第一位和最后一位的和。
如果直接利用回溯法,会TLE,所以还要想办法降低复杂度。这里我想的是计算出每个数只能和哪些数相加构成素数,只要在这些数中选取(同时也省去了判断和是否为素数的时间,除了第一位和最后一位)
最后一个要注意的点是:打印的最后一个数字没有空格
附上TLE代码和AC代码
AC:
//AC
#include<cstdio>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
int n;
int mark[30];
int A[20];
int res[20000000][20];
long long cnt = 0L;
int prime[11] = {3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
vector<int> option[21];
void init()
{
for (int i = 1; i <= 20; i++)
{
for (int j = 1; j <= 20; j++)
{
int t = i + j;
for (int k = 0; k < 11; k++)
{
if (prime[k] == t)
{
option[i].push_back(j);
break;
}
}
}
}
}
void dfs(int i)
{
if (i > n)
{
int p = A[1] + A[n];
bool flag = false;
for (int j = 0; j < 11; j++)
{
if (p == prime[j])
{
flag = true;
break;
}
}
if (flag)
{
for (int i = 1; i <= n; i++)
res[cnt][i] = A[i];
cnt++;
}
return;
}
for (int j = 0; j < option[A[i - 1]].size(); j++)
{
if (mark[option[A[i - 1]][j]] == 0 && option[A[i - 1]][j] <= n)
{
A[i] = option[A[i - 1]][j];
mark[option[A[i - 1]][j]] = 1;
dfs(i + 1);
mark[option[A[i - 1]][j]] = 0;
}
}
}
int main()
{
init();
int k = 1;
while (scanf("%d", &n) != EOF)
{
if (n >= 2 && n % 2 == 0)
{
memset(mark, 0, sizeof(mark));
memset(A, 0, sizeof(A));
mark[1] = 1; A[1] = 1;
cnt = 0;
dfs(2);
printf("Case %d:\n", k++);
for (long long i = 0L; i < cnt; i++)
{
for (int j = 1; j < n; j++)
printf("%d ", res[i][j]);
printf("%d", res[i][n]); //最后一个数字打印完没有空格
printf("\n");
}
printf("\n");
}
else if (n == 1)
{
printf("Case %d:\n", k++);
printf("1\n\n");
}
else
printf("Case %d:\n\n", k++);
}
return 0;
}
TLE:
//TLE
#include<cstdio>
#include<string.h>
#include<queue>
using namespace std;
int n;
int mark[30];
int A[20];
int res[200][20];
int cnt = 0;
int prime[12] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
void dfs(int i)
{
if (i > n)
{
int p = A[1] + A[n];
bool flag = false;
for (int j = 0; j < 12; j++)
{
if (p == prime[j])
{
flag = true;
break;
}
}
if (flag)
{
for (int i = 1; i <= n; i++)
res[cnt][i] = A[i];
cnt++;
}
return;
}
for (int j = 1; j <= n; j++)
{
if (mark[j] == 0)
{
int p1 = A[(i - 1) % n] + j;
bool flag = false;
for (int k = 0; k < 12; k++)
if (p1 == prime[k])
{
flag = true;
break;
}
if (flag)
{
A[i] = j;
mark[j] = 1;
dfs(i + 1);
mark[j] = 0;
}
}
}
}
int main()
{
int k = 1;
while (scanf("%d", &n) != EOF)
{
memset(mark, 0, sizeof(mark));
memset(A, 0, sizeof(A));
mark[1] = 1; A[1] = 1;
cnt = 0;
dfs(2);
printf("Case %d:\n", k++);
for (int i = 0; i < cnt; i++)
{
for (int j = 1; j <= n; j++)
printf("%d ", res[i][j]);
printf("\n");
}
printf("\n");
}
return 0;
}