知识点:剪枝,字典树,质数筛

题意:

给定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 2022-09-25 00:12  8号选手  阅读(251)  评论(0)    收藏  举报