靶形数独
这道题与 数独 几乎完全相同,只是需要计算靶形得分,可以直接使用一个 \(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;
}
但是这个方法不够优雅(其实快一些),我们可以推一推公式,找一找位置关系。
根据这幅图可以发现一个格子的分值是它到四条边(即整个大正方形的四条边)中最近的一条边的距离 \(+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;
}