P1549 [NOIP 1997 提高组] 棋盘问题

\[f(i) = \sum_{j=1}^{n^2} [i+j \in \mathbb{P}] \]

\[\sum_{i=1}^{n^2} f(i) = \Theta(\frac{n^4}{\log n}) \]

搜索+剪枝,最优性剪枝:当和超过最优解是剪枝,改变搜索顺序:优先枚举第一行和第一列。

\(n\) 很小时足够枚举所有状态,当 \(n\) 很大时观察到合法的解非常少,可能只有唯一解,搜到直接退出大概率正确。

#include <bits/stdc++.h>
#define umap unordered_map
#define vint vector<int>
#define ll long long
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define ull unsigned long long
#define uint unsigned int
#define rg register
#define il inline
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define sqr(x) ((x)*(x))
using namespace std;
const int INF=0x3f3f3f3f;
inline int read(){
    int w=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        w=(w<<1)+(w<<3)+(ch^48);
        ch=getchar();
    }
    return w*f;
}
inline void write(int x){
    if(x<0){
        putchar('-');
        x=-x;
    }
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
clock_t st=clock();
bool is_prime(int x){
    for(int i=2;i*i<=x;++i){
        if(x%i==0) return 0;
    }
    return 1;
}
int a[20][20],n,vis[114514];
vint gg[114514];
vector<pii> order;
int ans[20][20],sum=INF;
auto get_choice(int x,int y){
    set<int> res;
    rep(i,1,n*n) if(!vis[i]) res.insert(i);
    if(x!=1){
        set<int> tmp;
        for(int i:gg[a[x-1][y]]){
            if(res.find(i)!=res.end()) tmp.insert(i);
        }
        res=tmp;
    }
    if(y!=1){
        set<int> tmp;
        for(int i:gg[a[x][y-1]]){
            if(res.find(i)!=res.end()) tmp.insert(i);
        }
        res=tmp;
    }
    return res;
}
int cnt;
bool flag=0;
void dfs(int k,set<int> choice,int hang,int lie){
    if(flag) return;
    if(clock()-st>0.97*CLOCKS_PER_SEC) return;
    if(hang+lie>sum) return;
    if(k==n*n){
        int tmp=0;
        rep(i,1,n) tmp+=a[i][1]+a[1][i];
        if(tmp<sum){
            rep(i,1,n) rep(j,1,n) ans[i][j]=a[i][j];
            sum=tmp;
            if(n>=6) flag=1;
        }
        return;
    }
    for(auto i:choice){
        if(vis[i]) continue;
        auto [x,y]=order[k];
        a[x][y]=i,vis[i]=1;
        auto nxt=get_choice(order[k+1].first,order[k+1].second);
        dfs(k+1,nxt,x==1?hang+a[x][y]:hang,y==1?lie+a[x][y]:lie);
        vis[i]=0;
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    //freopen("in.txt","r",stdin);
    #endif
    cin>>n;
    for(int i=1;i<=n*n;++i){
        for(int j=1;j<=n*n;++j){
            if(i!=j){
                if(is_prime(i+j)) gg[i].push_back(j);
            }
        }
    }
    rep(i,1,n) order.push_back({1,i});
    rep(i,2,n) order.push_back({i,1});
    rep(i,2,n){
        rep(j,2,n) order.push_back({i,j});
    }
    order.push_back({1,1});
    // cout<<order.size()<<endl;
    // for(int i=1;i<=n*n;++i){
    //     for(auto j:gg[i]) cout<<j<<" ";
    //     cout<<endl;
    // }
    // cout<<endl;
    set<int> choice;
    choice.insert(1);
    dfs(0,choice,0,0);
    if(sum==INF||n==1) puts("NO");
    else{
        rep(i,1,n){
            rep(j,1,n){
                cout<<ans[i][j]<<" ";
            }
            cout<<endl;
        }
    }
    #ifndef ONLINE_JUDGE
    fprintf(stderr,"%f\n",1.0*clock()/CLOCKS_PER_SEC);
    #endif
    return 0;
}
posted @ 2025-08-01 16:55  vanueber  阅读(19)  评论(0)    收藏  举报