题意
对于数列 a1,a2,...,an ,如果满足所有相邻的两个数之和都为合数(非质数的话),则该数列被称作 anti-prime sequences。再对这个定义进行扩展,如果所有相邻的 d 个数之和为合数,则该数列就是 danti-prime sequences。
对给定正整数 n、m,满足 1 <= n < m <= 1000;给定正整数 d,满足 2 <= d <= 10。求 n,n+1,...,m 是否可以组成danti-prime sequences;若可以的话,给出按字典序的第一个 danti-prime sequences。
题解
这道题楼主卡了很久,一直没想通该怎么做。在网上搜相关的解答,都在说 DFS(也就是深度优先搜索),我知道这个算法啊,哪里用得上???只能说萌新一脸懵逼。不过后来我仔细地看了下各路大神的代码,才 AC 了,原来真的是 DFS!我下面描述下思路:
- 从数列
source
( n,n+1,...,m )中取出一个未被标记的数,放入(push)目标数列result
,并标记这个数; - 判断当前数列是否为 danti-prime sequences;
- 如果是,判断
result
数列元素数量是否达到m - n + 1
,若达到,结束逻辑,否则回到第 1 步; - 如果不是,则从
result
移出该数,取消该数的标记,再从source
中取下一个未被标记的数放入(push)result
。回到第 2 步。 - 在
result
数列元素数量达到m - n + 1
时,退出逻辑。
代码
#include <stdio.h>
#include <string.h>
// 素数表上限
#define PRIME_LIMIT 10000
// anti-prime sequences 数组上限
#define LIMIT 1005
typedef enum { FALSE = 0, TRUE = 1 } boolean;
int n, m, d; // 输入参数
boolean found; // 是否结束
boolean primes[PRIME_LIMIT]; // 素数表
boolean visited[LIMIT]; // 已访问列表
int result[LIMIT]; // 返回数组
void dfs(int degree);
boolean passWith(int num);
int main() {
int i, j;
memset(primes, TRUE, sizeof(primes));
primes[1] = FALSE;
for (i = 2; i < PRIME_LIMIT; ++i)
if (primes[i]) {
for (j = i * 2; j < PRIME_LIMIT; j += i)
primes[j] = FALSE;
}
while (scanf("%d%d%d", &n, &m, &d), n != 0 && m != 0 && d != 0) {
found = FALSE;
memset(visited, FALSE, sizeof(visited));
dfs(0); // 开始搜索
if (found) {
for (i = 0; i < m - n; ++i)
printf("%d,", result[i]);
printf("%d\n", result[i]);
} else
printf("No anti-prime sequence exists.\n");
}
}
/**
* DFS,当找到时停止搜索
*/
void dfs(int current) {
int i;
// 如果已经找到
if (found)
return;
// 如果当前数列不是 anti-prime sequence
if (!passWith(current))
return;
// 如果当前已经满了
if (current == m - n + 1) {
found = TRUE;
return;
}
for (i = n; i <= m && !found; ++i) {
if (visited[i]) continue; // 用过的就跳过(回溯的时候有用)
result[current] = i; // push 一个数进结果数列
visited[i] = TRUE;
dfs(current + 1); // 往下搜索
visited[i] = FALSE; // 搜索完去掉标记
}
}
/**
* 判断 end 前 2,3,...,d 个数是否和为合数。
* _ _ end - d _ ... _ end
*/
boolean passWith(int end) {
// d >= 2
if (end <= 1) return TRUE;
int sum;
int i, j;
sum = result[end - 1];
for (i = end - 2; i >= end - d; --i) {
sum += result[i];
if (primes[sum]) return FALSE;
}
return TRUE;
}
注
- 这题好难 T T
- 逗号表达式的值为最后一个子表达式
- Sicily 提交代码不支持注释…药丸