知识点:剪枝,字典树,质数筛
题意:
给定n,q,求得一个5×5的方阵,使得每行(从左到右),每列(从上到下),对角线,反对角线(从左到右)都为一个五位质数的矩阵(不包含前导零),其中每个质数,各位和为n,方阵左上第一个数为q。输出所有可能方阵,按照每个方阵25个数组成的数字大小排序输出。
题解思路:
第一遍做,先筛出五位质数,然后暴力枚举每行的五位,发现严重超时。
随后考虑字典树,字典树可以使得枚举的范围更精确。暴力枚举第一行符合的所有五位数,二到四行通过字典树寻找可能的分支。最后一行通过n的方程直接计算出来。最后判断合法。
然而还是超时,第三次,将判断合不合法的过程放在搜索当中减少不合理的搜索树。同时添加一些比较适当剪枝,比如第一行不能有零等。超时,但是六个点了
第四次,更换搜索中判断次序达到优化,添加inline,register等。进一步挣扎,终于九个点了,最后一点也勉强一秒内。虽然没过,但是我已经尽力挣扎了
正解大多数是一个点一个点,通过在棋盘上特殊的搜索顺序达到时间上的优化,一些特殊的路径可以充分利用每行每列每对角线的求和都是n的线索达到优化,但是问题是这样写,代码非常长。总之,这题挺毒瘤的,非常考验耐心和细心。同时,我在这道题上花了太多时间。其实能够达到复习和练习的目的时,我就应该跑了,而不是用不太优秀的方法死嗑。
题解代码:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<vector>
#include<string>
#include<cstring>
#include<algorithm>
#define rep(i,l,n) for(int i=(l);i<=(n);++i)
#define ll long long
using namespace std;
int t,n,q,flag;
int prime[3000],tot;
int p10[]={1,10,100,1000,10000,100000},trie[8000][12],id;
int trie2[10000][12],id2;
int ans[7][7],pans[7][7];
inline int find_num(int x,int i)
{
return (x/p10[5-i])%10;
}
inline void trie_insert(int x)
{
register int p=0,val;
for(register int i=1;i<=5;++i)
{
val=find_num(x,i);
if(trie[p][val]==0)trie[p][val]=++id;
p=trie[p][val];
}
return ;
}
inline void trie_insert2(int x)
{
register int p=0,val;
for(register int i=1;i<=5;++i)
{
val=find_num(x,5-i+1);
if(trie2[p][val]==0)trie2[p][val]=(++id2);
p=trie2[p][val];
}
return ;
}
inline int find_numsum(int x)
{
int ans=0;
rep(i,1,5)ans+=find_num(x,i);
return ans;
}
inline void find_prime()
{
register int i;
for(i=10000;i<=99997;++i)
{
if(find_numsum(i)!=n)continue;
int flag=1;
rep(j,2,sqrt(i))
{
if(i%j==0)
{
flag=0;
break;
}
}
if(flag)prime[++tot]=i;
}
}
inline bool pdzero(int x)
{
while(x)
{
int k=x%10;
if(k==0)return 1;
x/=10;
}
return 0;
}
inline bool pddiag(int i)
{
register int p=0,val;
rep(j,1,i)
{
val=ans[j][j];
if(trie[p][val]==0)return 0;
p=trie[p][val];
}
return 1;
}
inline bool pdbdiag(int cs)
{
register int p=0,val;
rep(j,1,cs)
{
val=ans[j][5-j+1];
if(trie2[p][val]==0)return 0;
p=trie2[p][val];
}
return 1;
}
inline bool pdhang(int cs,int i)
{
register int p=0,val;
rep(j,1,i)
{
val=ans[cs][j];
if(trie[p][val]==0)return 0;
p=trie[p][val];
}
return 1;
}
void dfs(int cs)
{
if(cs==5)
{
rep(i,1,5)ans[cs][i]=n-ans[1][i]-ans[2][i]-ans[3][i]-ans[4][i];
if(pdhang(5,5)&&pddiag(5)&&pdbdiag(5))
{
for(register int l1=1;l1<=5;++l1)
{
for(register int l2=1;l2<=5;++l2)putchar(ans[l1][l2]+'0');
putchar('\n');
}
putchar('\n');
flag=1;
}
return;
}
for(register int x1=1;x1<=9;++x1)
{
if(trie[pans[cs-1][1]][x1]==0)continue;
pans[cs][1]=trie[pans[cs-1][1]][x1];
ans[cs][1]=x1;
for(register int x2=0;x2<=9;++x2)
{
if(trie[pans[cs-1][2]][x2]==0)continue;
pans[cs][2]=trie[pans[cs-1][2]][x2];
ans[cs][2]=x2;
if(!pdhang(cs,2))continue;
if(cs==2&&!pddiag(cs))continue;
if(cs==4&&!pdbdiag(cs))continue;
for(register int x3=0;x3<=9;++x3)
{
if(trie[pans[cs-1][3]][x3]==0)continue;
pans[cs][3]=trie[pans[cs-1][3]][x3];
ans[cs][3]=x3;
if(!pdhang(cs,3))continue;
if(cs==3&&!pddiag(cs))continue;
if(cs==3&&!pdbdiag(cs))continue;
for(register int x4=0;x4<=9;++x4)
{
if(trie[pans[cs-1][4]][x4]==0)continue;
pans[cs][4]=trie[pans[cs-1][4]][x4];
ans[cs][4]=x4;
if(!pdhang(cs,4))continue;
if(cs==4&&!pddiag(cs))continue;
if(cs==2&&!pdbdiag(cs))continue;
for(register int x5=0;x5<=9;++x5)
{
if(trie[pans[cs-1][5]][x5]==0)continue;
if(x5!=n-x1-x2-x3-x4)continue;
pans[cs][5]=trie[pans[cs-1][5]][x5];
ans[cs][5]=x5;
if(!pdhang(cs,5))continue;
dfs(cs+1);
}
}
}
}
}
return ;
}
int main()
{
scanf("%d%d",&n,&q);
find_prime();
register int i=0;
for(i=1;i<=tot;++i)
{
trie_insert(prime[i]);
trie_insert2(prime[i]);
}
i=upper_bound(prime+1,prime+1+tot,q*10000)-prime;
for(i;i<=tot;++i)
{
int x=prime[i];
if((find_num(x,1)!=q||pdzero(x)))continue;
rep(i,1,5)
{
int ts=find_num(x,i);
pans[1][i]=trie[0][ts];
ans[1][i]=ts;
}
dfs(2);
}
if(!flag)puts("NONE");
system("pause");
return 0;
}
posted on
浙公网安备 33010602011771号