靶形数独

这道题与 数独 几乎完全相同,只是需要计算靶形得分,可以直接使用一个 \(9\times 9\) 的矩阵,如下代码

#include<bits/stdc++.h>
using namespace std;
const int num[9][9]={
{6,6,6,6,6,6,6,6,6},
{6,7,7,7,7,7,7,7,6},
{6,7,8,8,8,8,8,7,6},
{6,7,8,9,9,9,8,7,6},
{6,7,8,9,10,9,8,7,6},
{6,7,8,9,9,9,8,7,6},
{6,7,8,8,8,8,8,7,6},
{6,7,7,7,7,7,7,7,6},
{6,6,6,6,6,6,6,6,6}};
using PII=pair<int,int>;
int row[9],col[9],ce[3][3],cur,mp[1<<9],ones[1<<9],ans;
bool s[9][9];
int get(int a,int b){
    return row[a]&col[b]&ce[a/3][b/3];
}
void dfs(int dep,int score){
    if(dep==cur+1){
        ans=max(ans,score);
        return;
    }
    int minv=10,a,b;
    for(int i=0;i<9;++i)
        for(int j=0;j<9;++j)
            if(s[i][j]==0&&ones[get(i,j)]<minv){
                a=i;
                b=j;
                minv=ones[get(i,j)];
            }
    for(int can=get(a,b);can;can-=can&-can){
        int x=mp[can&-can];
        row[a]-=1<<x;
        col[b]-=1<<x;
        ce[a/3][b/3]-=1<<x;
        s[a][b]=x+1;
        dfs(dep+1,score+num[a][b]*(x+1));
        row[a]+=1<<x;
        col[b]+=1<<x;
        ce[a/3][b/3]+=1<<x;
        s[a][b]=0;
    }
}
int main(){
    for(int i=1;i<1<<9;++i)ones[i]=ones[i^(i&-i)]+1;
    for(int i=0;i<9;++i)mp[1<<i]=i;
    for(int i=0;i<9;++i)row[i]=col[i]=(1<<9)-1;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)ce[i][j]=(1<<9)-1;
    int k=0,res=0;
    for(int i=0;i<9;++i)
        for(int j=0;j<9;++j){
            int c;
            scanf("%d",&c);
            s[i][j]=c;
            if(c!=0){
                res+=num[i][j]*c;
                c--;
                row[i]-=1<<c;
                col[j]-=1<<c;
                ce[i/3][j/3]-=1<<c;
            }
            else ++cur;
        }
    dfs(1,0);
    printf("%d",ans?ans+res:-1);
    return 0;
}

但是这个方法不够优雅(其实快一些),我们可以推一推公式,找一找位置关系。

19_1add32be19-靶子.jpe

根据这幅图可以发现一个格子的分值是它到四条边(即整个大正方形的四条边)中最近的一条边的距离 \(+6\),比如中间的金色格子到上、下、左、右距离都为 \(4\)\(4+6=10\)\((3,4)\) 的格子到上、下、左、右距离分别为 \(3,5,4,4\),所以 \(3+6=9\)

#include<bits/stdc++.h>
using namespace std;
using PII=pair<int,int>;
int row[9],col[9],ce[3][3],cur,mp[1<<9],ones[1<<9],ans;
bool s[9][9];
int get(int a,int b){
    return row[a]&col[b]&ce[a/3][b/3];
}
int get_score(int x, int y, int c){
    int t=x;
    if(x>4)t=8-x;
    if(y<t)t=y;
    if(t+y>8)t=8-y;
    t+=6;
    return t*c;
}
void dfs(int dep,int score){
    if(dep==cur+1){
        ans=max(ans,score);
        return;
    }
    int minv=10,a,b;
    for(int i=0;i<9;++i)
        for(int j=0;j<9;++j)
            if(s[i][j]==0&&ones[get(i,j)]<minv){
                a=i;
                b=j;
                minv=ones[get(i,j)];
            }
    for(int can=get(a,b);can;can-=can&-can){
        int x=mp[can&-can];
        row[a]-=1<<x;
        col[b]-=1<<x;
        ce[a/3][b/3]-=1<<x;
        s[a][b]=x+1;
        dfs(dep+1,score+get_score(a,b,x+1));
        row[a]+=1<<x;
        col[b]+=1<<x;
        ce[a/3][b/3]+=1<<x;
        s[a][b]=0;
    }
}
int main(){
    for(int i=1;i<1<<9;++i)ones[i]=ones[i^(i&-i)]+1;
    for(int i=0;i<9;++i)mp[1<<i]=i;
    for(int i=0;i<9;++i)row[i]=col[i]=(1<<9)-1;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)ce[i][j]=(1<<9)-1;
    int k=0,res=0;
    for(int i=0;i<9;++i)
        for(int j=0;j<9;++j){
            int c;
            scanf("%d",&c);
            s[i][j]=c;
            if(c!=0){
                res+=get_score(i,j,c);
                c--;
                row[i]-=1<<c;
                col[j]-=1<<c;
                ce[i/3][j/3]-=1<<c;
            }
            else ++cur;
        }
    dfs(1,0);
    printf("%d",ans?ans+res:-1);
    return 0;
}
posted @ 2023-05-13 20:59  wscqwq  阅读(50)  评论(0编辑  收藏  举报