P1074 靶形数独

P1074 靶形数独

dfs 优化搜索顺序

我们可以想到一种方法,每次找可以填的数最少的格子进行dfs。

离线 85pts

在线 100pts

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct data{int x,y;};
const int maxn=100; //由于未知原因,我的代码需要开10倍的数组不然会RE(???)
int ans=-1,val[maxn][maxn],score[maxn][maxn],l[maxn],r[maxn]; //val,score:填入的数,和给出的分数 l,r:该行/列已填几个数
bool use1[maxn][maxn],use2[maxn][maxn],use3[10][10][maxn],vis[maxn][maxn]; //use1,2,3:行、列、九宫格限制可填的数
inline int blo(int &a) {return (a-1)/3+1;} //求所在块的编号
inline data find(){ //在线找可填数最小的点
    int mxl=-1,mxr=-1,L,R;
    for(int i=1;i<=9;++i) if(l[i]>mxl&&l[i]<9) L=i,mxl=l[i];
    for(int i=1;i<=9;++i) if(r[i]>mxr&&!val[L][i]) R=i,mxr=r[i];
    return (data){L,R};
}
inline void dfs(int step,int tot,data node){
    if(step==81) {ans=ans>tot ? ans:tot; return ;}
    int x=node.x,y=node.y;
    for(int i=1;i<=9;++i){
        if(use1[x][i]||use2[y][i]||use3[blo(x)][blo(y)][i]) continue;
        val[x][y]=i;
        ++l[x]; ++r[y];
        use1[x][i]=1;
        use2[y][i]=1;
        use3[blo(x)][blo(y)][i]=1;
        dfs(step+1,tot+i*score[x][y],find());
        val[x][y]=0;
        --l[x]; --r[y];
        use1[x][i]=0;
        use2[y][i]=0;
        use3[blo(x)][blo(y)][i]=0; //回溯
    }
}
int main(){
    int tot=0,cnt=0;
    for(int i=1;i<=9;++i)
        for(int j=1;j<=9;++j){
            scanf("%d",&val[i][j]);
            if(!val[i][j]) continue;
            ++cnt; ++l[i]; ++r[j];
            use1[i][val[i][j]]=1; 
            use2[j][val[i][j]]=1;
            use3[blo(i)][blo(j)][val[i][j]]=1;
        }
    for(int i=5;i>=1;--i){
        int x1=i,x2=10-i,x3=i,x4=10-i;
        int y1=i,y2=i,y3=10-i,y4=10-i;
        for(int j=10-i;j>=i;--j){
            score[x1][y1]=i+5;
            score[x2][y2]=i+5;
            score[x3][y3]=i+5;
            score[x4][y4]=i+5;
            if(val[x1][y1]&&!vis[x1][y1]) tot+=val[x1][y1]*score[x1][y1],vis[x1][y1]=1;
            if(val[x2][y2]&&!vis[x2][y2]) tot+=val[x2][y2]*score[x2][y2],vis[x2][y2]=1;
            if(val[x3][y3]&&!vis[x3][y3]) tot+=val[x3][y3]*score[x3][y3],vis[x3][y3]=1;
            if(val[x4][y4]&&!vis[x4][y4]) tot+=val[x4][y4]*score[x4][y4],vis[x4][y4]=1;
            ++x1; ++y2; --y3; --x4;
        } //按照题意给出分数
    }
    dfs(cnt,tot,find());
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/kafuuchino/p/9588329.html