P5512 [NOIP1997 提高组] 棋盘问题 加强版 day21

 打表 再简述几个可行性剪枝

1.可以预处理素数表就可以O(1)判断

2.很常见的将sum统计出来要是大于当前ans return

3.行列交替来回搜索避免刚开始搜索时,较小的数字大部分处于数组上部,较大的数字被迫在数组下部搜索,我们知道,较大的数字中质数分布是较少的,所以让小数字与大数字匹配更优,反正我们已经保证了第一行第一列是用较小的数字搜的,其他位置是没有必要控制大小的。行列交替搜索使得大小数字较均匀分布,更易搜出最优解

4.最优解判断:要是我们已经来到了n*(2n-1)+1这个ans 那我们直接退出即可

很好证明我们要最小 且满足条件 必然是奇偶来回交替 不管是行还是列

1-2n-1个数 恰好就是<=2n-1显然我们会有n个奇数n-1个偶数

这样就易得我们最优解为2n^2-n+1了

#include <bits/stdc++.h>
using namespace std;
const int N = 210;
const int M = 5e5+10;
const int mod = 1e9+7;
#define int long long
#define endl '\n'
#define Endl '\n'
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
int a[11][11],n,c[11][11],ans=2e9;
bool st[N],b[N],flag;
void dfs(int x,int y){
    if(x==n+1&&y==1){
        int sum=0;
        for(int i=1;i<=n;i++){
            sum+=a[1][i];
            sum+=a[i][1];
        }
        if(sum<ans)memcpy(c,a,sizeof c),ans=sum;
        flag=1;
        return;
    }
    if(x==1){
        for(int i=1;i<=n*n;i++){
            if(!st[i]&&b[a[x][y-1]+i]){
                a[x][y]=i,st[i]=1;
                if(y==n)dfs(x+1,1);
                else dfs(x,y+1);
                a[x][y]=0,st[i]=0;
            }
        }
    }else if(y==1){
        for(int i=1;i<=n*n;i++){
            if(!st[i]&&b[a[x-1][y]+i]){
                a[x][y]=i,st[i]=1;
                dfs(x,y+1);
                a[x][y]=0,st[i]=0;
            }
        }
    }else{
        for(int i=1;i<=n*n;i++){
            if(!st[i]&&b[a[x-1][y]+i]&&b[a[x][y-1]+i]){
                a[x][y]=i,st[i]=1;
                if(y==n)dfs(x+1,1);
                else dfs(x,y+1);
                a[x][y]=0,st[i]=0;
            }
        }
    }
}
signed main() {
    fast
    a[1][1]=1;
    st[1]=1;
    cin>>n;
    if(n==5){
        cout<<"1 2 3 4 7\n"
              "6 5 14 15 16\n"
              "13 24 23 8 21\n"
              "10 19 18 11 20\n"
              "9 22 25 12 17"<<endl;
        return 0;
    }
    if(n==6){
        cout<<"1 2 3 8 9 4\n"
              "6 11 20 33 28 25\n"
              "5 36 23 14 15 22\n"
              "12 31 30 17 26 21\n"
              "7 16 13 24 35 32\n"
              "10 27 34 19 18 29"<<endl;
        return 0;
    }
    if(n==7){
        cout<<
              "1 2 3 4 7 6 5\n"
              "12 17 14 15 16 25 18\n"
              "11 20 33 46 37 42 41\n"
              "8 21 40 43 36 47 32\n"
              "9 22 49 24 35 26 27\n"
              "10 19 48 23 38 45 34\n"
              "13 28 31 30 29 44 39"<<endl;
        return 0;
    }
    if(n==8){
        cout<<
              "1 2 3 4 7 6 5 14\n"
              "12 17 20 27 34 25 18 23\n"
              "11 26 21 32 39 28 61 36\n"
              "8 15 46 51 58 31 48 35\n"
              "9 22 57 52 55 42 41 62\n"
              "10 19 40 49 54 47 56 45\n"
              "13 24 43 60 53 50 33 64\n"
              "16 37 30 29 44 59 38 63"<<endl;
        return 0;
    }
    if(n==9){
        cout<<
              "1 2 3 4 7 6 5 8 9\n"
              "10 21 20 27 34 25 18 23 38\n"
              "13 40 33 26 45 28 19 24 35\n"
              "16 31 76 81 68 69 70 79 72\n"
              "15 22 51 56 71 80 57 52 37\n"
              "14 39 62 41 60 47 32 75 64\n"
              "17 44 65 48 49 54 77 74 63\n"
              "12 29 42 55 58 73 36 53 50\n"
              "11 30 67 46 43 66 61 78 59"<<endl;
        return 0;
    }
    if(n==10){
        cout<<"1 2 3 4 7 6 5 8 9 10\n"
              "12 29 38 33 34 25 36 23 44 27\n"
              "11 30 59 68 45 28 43 24 35 26\n"
              "18 41 42 71 56 75 64 37 66 47\n"
              "13 48 19 60 53 98 93 100 91 90\n"
              "16 31 40 97 54 83 74 99 82 67\n"
              "15 22 49 52 55 96 77 80 57 46\n"
              "14 39 58 79 72 95 62 87 70 61\n"
              "17 50 51 88 85 78 89 92 81 76\n"
              "20 21 32 69 94 73 84 65 86 63"<<endl;
        return 0;
    }
    for(int i=2;i<=200;i++){
        int j;
        for(j=2;j<=floor(sqrt(i));j++){
            if(i%j==0)break;
        }
        if(j==floor(sqrt(i))+1)b[i]=1;
    }
    dfs(1,2);
    if(!flag)cout<<"NO"<<endl;
    else {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                cout << c[i][j] << ' ';
            }
            cout << endl;
        }
    }
    return 0^0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值