101. 填数
★ 输入文件:tianshu.in
输出文件:
tianshu.out
简单对比
时间限制:2 s 内存限制:128 MB
【问题描述】
在一个 N*N 的棋盘上( 1 ≤ N ≤ 10 ),填入 1 , 2 ,…, N*N 共 N*N 个数,使得任意两个相邻的数之和为素数。
例如:当 N=2 时,有:
1 | 2 |
4 | 3 |
当 N=4 时,一种可以填写的方案如下:在这里我们约定:左上角的格子里必须填数字 1 。
1 | 2 | 11 | 12 |
4 | 9 | 8 | 5 |
7 | 10 | 3 | 14 |
6 | 13 | 16 | 15 |
【输入格式】
文件只有一行为一个正整数n
【输出格式】
输出文件有n行,每行有n个数,中间用一个空格隔开
如有多种解,设a[i,j]为解的第i行第j个数,则输出以i为第一关键字,j为第二关键字,小数在前的那一种方案;若无解,则输出“NO”。
【输入输出样例】
输入:
2
输出:
1 2
4 3
搜索。。DFS+回溯。。但是在搜索n=11时,会超时。。原来数据中还有11.。目前还没有想到好的剪枝。直接对11进行打表了。
#include<cstdio>
#include<cmath>
using namespace std;
int ans[13][13];
bool vis[150];
int prim[300];
void get_prim(){
int i;
for(int n=2;n<300;n++){
for( i=2;i<=sqrt(n);i++)
if(n%i==0) break;
if(i>sqrt(n))
prim[n]=true;
}
}
int n,flag;
void dfs(int x,int y){
if(flag) return ;
if(x==n+1&&y==1){
flag=1; return ;
}
for(int i=2;i<=n*n;i++){
if(flag) return ;
if(!vis[i]){
if(y>1&&!prim[i+ans[x][y-1]]) continue;
if(x>1&&!prim[i+ans[x-1][y]]) continue ;
ans[x][y]=i;
vis[i]=true;
if(y==n) {
dfs(x+1,1);
}
else{
dfs(x,y+1);
}
vis[i]=false;
}
}
}
int main(){
freopen("tianshu.in","r",stdin);
freopen("tianshu.out","w",stdout);
get_prim();
scanf("%d",&n);
if(n==11){
printf("1 2 3 4 7 6 5 8 9 10 13\n");
printf("12 11 20 27 16 25 18 23 14 33 28\n");
printf("17 26 21 32 15 22 19 24 29 38 45\n");
printf("30 41 62 35 44 39 34 37 42 59 68\n");
printf("31 48 65 36 53 50 63 46 55 54 83\n");
printf("40 49 102 47 56 51 76 61 52 85 66\n");
printf("43 58 79 60 71 80 87 70 57 82 91\n");
printf("64 73 120 103 96 77 104 93 106 67 100\n");
printf("109 118 121 90 101 72 107 74 117 112 81\n");
printf("84 115 108 89 78 95 86 105 94 99 92\n");
printf("97 114 119 110 113 116 111 88 69 98 75\n");
return 0;
}
flag=0;
vis[1]=true;
ans[1][1]=1;
dfs(1,2);
if(flag){
for(int i=1;i<=n;i++){
for(int j=1;j<n;j++)
printf("%d ",ans[i][j]);
printf("%d\n",ans[i][n]);
}
}
else{
printf("NO\n");
}
return 0;
}