[解题报告][搜索+剪枝技巧]幻方
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[解题报告][搜索+剪枝技巧]幻方相关的知识,希望对你有一定的参考价值。
【Description】
请解决一个 N 阶幻方。(N=3或4)
为了凑够 15 字补一个幻方的简介好了。给定 N*N 个数,把它们填入 N*N 的方格中,使每
行每列和两个斜对角线里数的和都相等。
【Input】
第一行一个正整数 N
第二行 N*N 个整数,代表要填入幻方中的数
【Output】
N 行每行 N 个整数,用空格隔开,代表填好的幻方。
如果有多组解,输出任意一组即可。
保证有解。
【Sample Input1】
3
9 9 9 9 9 9 9 9 9
【Sample Output1】
9 9 9
9 9 9
9 9 9
【Sample Input2】
3
1 2 3 4 5 6 7 8 9
【Sample Output2】
2 7 6
9 5 1
4 3 8
思路:
1.如果n=3,可以暴力枚举,复杂度为O(9!)
2.n=4时,直接暴力4*4的话一定会挂,可以只暴力8个格子
# # # #
# 1 # 8
# 6 2 7
# 5 4 3
剪枝1:只搜8个格子(上)
剪枝2:按照一定的顺序搜索,当搜索到一些特定的格子就能推算出某个#的数值,如果#不在可用数字范围内,可以直接return
优化1:记录每个数字出现的个数,判断是否在可用范围内时直接判断个数,注意最好不要用map(似乎会消耗大量时间),可以用unordered_map或者自己离散化。
幻方和=所有数字总和/n
代码:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <algorithm> 4 #include <map> 5 #include <ctime> 6 #include <cstring> 7 using namespace std; 8 int pl[20],use[20]; 9 int n,pn,sum; 10 int hf[5][5]; 11 int mm[20],mmct[20]; 12 int mp=0; 13 #define covidx(x,y) (x-1)*4+(y-1) 14 void prints() 15 { 16 for(int i=1; i<=n; i++) 17 for(int j=1; j<=n; j++) 18 { 19 printf("%d%c",hf[i][j],j==n?‘\n‘:‘ ‘); 20 } 21 } 22 inline int getid(int a) 23 { 24 for(int i=0; i<mp; i++) 25 { 26 if(mm[i]==a) return i; 27 } 28 return 19; 29 } 30 inline int check() 31 { 32 int t1=0,t2=0,t3=0,t4=0; 33 for(int i=1; i<=n; i++) 34 { 35 t1+=hf[i][i]; 36 t2+=hf[i][n-i+1]; 37 for(int j=1; j<=n; j++) 38 { 39 t3+=hf[i][j]; 40 t4+=hf[j][i]; 41 } 42 if(t3!=t4 || t3!=sum || t4!=sum) return 0; 43 else if(i!=n) 44 t3=t4=0; 45 } 46 if(t2!=t1) return 0; 47 if(t3!=t2) return 0; 48 if(t2!=sum) return 0; 49 return 1; 50 } 51 void fuck3(int x,int y) 52 { 53 54 if(x==4) 55 { 56 if(check()) 57 { 58 prints(); 59 exit(0); 60 } 61 else 62 return; 63 } 64 int tx,ty; 65 for(int i=1; i<=pn; i++) 66 { 67 if(!use[i]) 68 { 69 use[i]=1; 70 hf[x][y]=pl[i]; 71 if(y==3) 72 { 73 ty=1; 74 tx=x+1; 75 } 76 else 77 { 78 ty=y+1; 79 tx=x; 80 } 81 fuck3(tx,ty); 82 use[i]=0; 83 } 84 } 85 } 86 87 /* 88 3 6 8 8 89 #7 1 8 8 90 7 6 2 7 91 5 5 4 3 92 93 1 2 3 4 94 5 6 7 8 95 9 10 11 12 96 13 14 15 16 97 */ 98 int xyidx[9][2]= {{-1,-1},{2,2},{3,3},{4,4},{4,3},{4,2},{3,2},{3,4},{2,4}}; 99 int deps[16][8]= 100 { 101 {1,2,3},{1,6,5},{-1,-2,-4},{8,7,3}, 102 {-1,-9,-13},{0},{-5,1,8},{0}, 103 {6,2,7},{0},{0},{0}, 104 {5,4,3},{0},{0},{0} 105 }; 106 int lin[16][4]= 107 { 108 {0},{0},{0},{3}, 109 {0},{0},{4},{7}, 110 {5},{2},{0},{9}, 111 {0},{13},{0},{1} 112 }; 113 114 115 116 int prelin(int idx) 117 { 118 int i,j; 119 i=0; 120 if(idx>0) 121 idx=(xyidx[idx][0]-1)*4+xyidx[idx][1]-1; 122 else 123 idx=-idx; 124 while(lin[idx][i]!=0) 125 { 126 int cpa=lin[idx][i]; 127 int x=(cpa-1)/4+1; 128 int y=(cpa-1)%4+1; 129 int nsum=0; 130 j=0; 131 cpa-=1; 132 while(deps[cpa][j]!=0) 133 { 134 int dalao=deps[cpa][j],x,y; 135 if(dalao>0) 136 { 137 x=xyidx[dalao][0]; 138 y=xyidx[dalao][1]; 139 } 140 else 141 { 142 dalao=-dalao; 143 dalao-=1; 144 x=dalao/4+1; 145 y=dalao%4+1; 146 } 147 nsum+=hf[x][y]; 148 j++; 149 } 150 int id; 151 if(mmct[id=getid(sum-nsum)]>0) 152 { 153 hf[x][y]=sum-nsum; 154 mmct[id]--; 155 prelin(-(covidx(x,y))); 156 } 157 else 158 { 159 return 0; 160 } 161 i++; 162 } 163 return 1; 164 } 165 void dfs4(int idx) 166 { 167 if(idx==9) 168 { 169 if(check()) 170 { 171 prints(); 172 exit(0); 173 } 174 else 175 { 176 return; 177 } 178 } 179 //给idx填数 180 int x=xyidx[idx][0]; 181 int y=xyidx[idx][1]; 182 int bnaive[20]; 183 memcpy(bnaive,mmct,sizeof(mmct)); 184 int id; 185 for(int i=1; i<=pn; i++) 186 { 187 if(mmct[id=getid(pl[i])]>0) 188 { 189 mmct[id]--; 190 hf[x][y]=pl[i]; 191 if(prelin(idx)==0) 192 { 193 memcpy(mmct,bnaive,sizeof(mmct)); 194 continue; 195 } 196 dfs4(idx+1); 197 memcpy(mmct,bnaive,sizeof(mmct)); 198 } 199 } 200 } 201 int main() 202 { 203 //freopen("magicsquare.in","r",stdin); 204 //freopen("magicsquare.out","w",stdout); 205 scanf("%d",&n); 206 pn=n*n; 207 for(int i=1; i<=pn; i++) 208 { 209 scanf("%d",&pl[i]); 210 sum+=pl[i]; 211 } 212 sort(&pl[1],&pl[pn+1]); 213 if(n==3) 214 fuck3(1,1); 215 else 216 { 217 sum/=4; 218 for(int i=1; i<=pn; i++) 219 { 220 int id; 221 if((id=getid(pl[i]))==19) 222 { 223 mm[mp]=pl[i]; 224 mmct[mp]=1; 225 mp++; 226 } 227 else 228 { 229 mmct[id]++; 230 } 231 } 232 dfs4(1); 233 } 234 }
以上是关于[解题报告][搜索+剪枝技巧]幻方的主要内容,如果未能解决你的问题,请参考以下文章