题解:洛谷 P1218 特殊的质数肋骨
【题目来源】
洛谷:P1218 [USACO1.5] 特殊的质数肋骨 Superprime Rib - 洛谷
【题目描述】
农民约翰的母牛总是产生最好的肋骨。你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们。
农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组成一个质数。
举例来说:7 3 3 1 全部肋骨上的数字 7331 是质数;三根肋骨 733 是质数;二根肋骨 73 是质数;当然,最后一根肋骨 7 也是质数。7331 被叫做长度 4 的特殊质数。
写一个程序对给定的肋骨的数目 n,求出所有的特殊质数。1 不是质数。
【输入】
一行一个正整数 n。
【输出】
按顺序输出长度为 n 的特殊质数,每行一个。
【输入样例】
4
【输出样例】
2333
2339
2393
2399
2939
3119
3137
3733
3739
3793
3797
5939
7193
7331
7333
7393
【核心思想】
-
问题分析:给定长度 \(n\),要求找出所有长度为 \(n\) 的"特殊质数"——从最高位到最低位逐位截断后得到的每个前缀都是质数。例如 \(7331\) 是特殊质数,因为 \(7\)、\(73\)、\(733\)、\(7331\) 均为质数。这是一个DFS 逐位构造 + 质数剪枝问题。
-
算法选择:
- 逐位 DFS 构造:从最高位开始,每次在已有前缀后添加一位数字(\(1 \sim 9\)),形成新数后判断是否为质数
- 质数剪枝:若当前前缀不是质数,则直接剪枝,不再向下扩展(因为任何以该前缀开头的数都不可能是特殊质数)
- 试除法判质:对每个构造出的数用 \(\sqrt{n}\) 范围内的试除法判断质数
-
关键步骤:
- 读入:\(n\)(目标长度)
- DFS 函数
dfs(cnt, num):cnt:当前已构造的位数num:当前前缀数值- 遍历 \(i\) 从 \(1\) 到 \(9\):
tmp = num * 10 + i:构造新数- 若
isPrime(tmp)为真:- 若
cnt == n:已到达目标长度,输出tmp - 否则:
dfs(cnt + 1, tmp)继续向下构造
- 若
- 启动搜索:
dfs(1, 0),从 1 位数字、前缀 0 开始
-
时间/空间复杂度:
- 时间复杂度:\(O(9^n \cdot \sqrt{10^n})\),实际因大量剪枝远小于此值
- 空间复杂度:\(O(n)\),递归深度为 \(n\)
-
DFS 逐位构造的核心思想:
- 前缀保持性:特殊质数的任意前缀也必须是特殊质数,因此可以从高位到低位逐位构造,每步验证
- 强剪枝效果:一位数质数只有 \(2, 3, 5, 7\) 四个,以此为前缀的二位数质数更少,搜索树分支极少
- 逐层筛选:每深入一层就过滤掉大量非质数分支,\(n\) 较大时依然高效
- 无后效性:当前前缀是否为质数只取决于前缀本身,与后续添加的数字无关
- 适用于逐位构造、前缀约束、强剪枝搜索类问题
【解题思路】

【算法标签】
普及- #DFS-一维
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, st=1, ed=9, t, tmp;
bool isPrime(int n) // 定义质数模板
{
if (n<2) return false;
for (int i=2; i<=sqrt(n); i++) {
if (n%i==0) return false;
}
return true;
}
void dfs(int cnt, int num) // 定义深搜函数
{
for (int i=1; i<=9; i++) { // 遍历1-9
int tmp = num * 10 + i; // 使用临时变量tmp记录进位后的数字
if (isPrime(tmp)) { // 判断这个数字是否是质数
if (cnt==n) { // 判断此时的cnt是否为n
cout << tmp << endl; // 如果是则输出tmp
} else { // 如果cnt还不是n,但因为当前数字已经是质数,所以要进一步搜索
dfs(cnt+1, tmp); // cnt自增1,使用tmp继续搜索
}
}
}
}
int main()
{
cin >> n; // 输入n
dfs(1, 0); // 使用深搜,1表示1位数字,0表示起始数字为0
return 0;
}
【运行结果】
4
2333
2339
2393
2399
2939
3119
3137
3733
3739
3793
3797
5939
7193
7331
7333
7393
浙公网安备 33010602011771号