题目
啊咧
提交代码的时候,第一次PE错误,我想了一下可能是 行末打回车前的空格在作怪,一改,还真是。
输出结果的末尾打空格也是不行的,比赛要注意咯。
2020/4/6补充 : 代码测试时间(没错,1000多将近2000的当然是我的思路啦)
AC代码
//4/1/20:09 _ 20:40
//@reasonbao
//comn on, you guy! do it!
#include <iostream>
#include <cstdio>
using namespace std;
bool PrimeJudge(int n) {
bool is_prime = true;
for (int i = 2; i <= n-1; i++) {
if (n % i == 0) {
is_prime = false;
break;
}
}
return is_prime;
}
//回溯法
void Operate(int n, int *A, int cur) {
if (cur == n) { //能递归到这,说明满足条件
for (int i = 0; i < n; i++) {
// cout << A[i] << " "; PE错误
if (i != n-1) cout << A[i] << " ";
else cout << A[i] << endl;
}
// cout << endl;
}
for (int i = 2; i <= n; i++) { //A[cur] 尝试填入各种情况
bool is_ok = true;
for (int j = 0; j < cur; j++) {
if (i == A[j] ) { //填过的情况
is_ok = false;
break;
}
if (!PrimeJudge(A[cur-1] + i)) { //与前一个数相加 非素数情况
is_ok = false;
break;
}
}
if (cur == n-1) { //填最后一个数的情况,判断首尾相加是否素数
if (!PrimeJudge(i + A[0])) is_ok = false;
}
if (is_ok) {
A[cur] = i;
Operate(n,A,cur+1);
}
}
}
int main() {
int A[20];
int n;
int kase = 0;
while (scanf("%d", &n) != EOF) {
kase++;
if (kase > 1) cout << endl;
// cout << PrimeJudge(n) << endl;
printf("Case %d:\n", kase);
A[0] = 1; //枚举以1开头的情况即可
Operate(n, A, 1);
}
return 0;
}
代码2.0 学习了刘汝佳的思路,十分清晰明了,而且Time直接180ms了
//4/6 15:30
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 16;
int vis[maxn]; //数字是否使用过的标志
int is_prime(int n) {
if (n<=1 ) return 0;
for (int i = 2; i <= n-1; i++) { //素数判断只要遍历到开方处就行了
if (n % i == 0) {
return 0;
}
}
return 1;
}
//生成-测试法的最坏情况非常大,故采用回溯法
void Operate(int n, int *A, int cur) {
if (cur == n && is_prime(A[0] + A[n-1])) { //注意还没判断头尾
for (int i = 0; i < n; i++) {
if (i != n-1) printf("%d ", A[i]); //速度快,相比 cout
else printf("%d\n", A[i]);
}
}
else {
for (int i = 2; i <= n; i++) { //往A[i]中填入各种情况
if (!vis[i] && is_prime(A[cur-1] + i)) {
A[cur] = i;
vis[i] = 1;
Operate(n,A,cur+1);
vis[i] = 0; //用完即空闲,置为0
}
}
}
}
int main() {
int A[maxn];
int n;
int kase = 0;
while (scanf("%d", &n) != EOF) {
kase++;
if (kase > 1) printf("\n");
printf("Case %d:\n", kase);
memset(vis,0,sizeof(vis));
A[0] = 1; //枚举以1开头的情况即可
Operate(n, A, 1);
}
return 0;
}
代码3.0 TQL,再补充了刘汝佳老师的思路,Time = 110ms了
//4/6 15:30
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 16;
int g_vis[maxn]; //数字是否使用过的标志
int g_isp[maxn*2]; //素数表
int is_prime(int n) {
if (n<=1 ) return 0;
for (int i = 2; i <= floor(sqrt(n) + 0.5); i++) { //素数判断只要遍历到开方处就行了
if (n % i == 0) { //floor()-向下取整,当n较大时可避免整数变成xxx.9999
return 0;
}
}
return 1;
}
//生成-测试法的最坏情况非常大,故采用回溯法
void Operate(int n, int *A, int cur) {
if (cur == n && g_isp[A[0] + A[n-1]]) { //注意还没判断头尾
for (int i = 0; i < n; i++) {
if (i != n-1) printf("%d ", A[i]); //速度快,相比 cout
else printf("%d\n", A[i]);
}
}
else {
for (int i = 2; i <= n; i++) { //往A[i]中填入各种情况
if (!g_vis[i] && g_isp[A[cur-1] + i]) {
A[cur] = i;
g_vis[i] = 1;
Operate(n,A,cur+1);
g_vis[i] = 0; //用完即空闲,置为0
}
}
}
}
int main() {
int A[maxn];
int n;
int kase = 0;
//生成素数表
for (int i = 0; i < maxn*2; i++) {
g_isp[i] = is_prime(i);
}
while (scanf("%d", &n) != EOF) {
kase++;
if (kase > 1) printf("\n");
printf("Case %d:\n", kase);
memset(g_vis,0,sizeof(g_vis));
A[0] = 1; //枚举以1开头的情况即可
Operate(n, A, 1);
}
return 0;
}