闲谈:和数独规则差不多--然后可以直接按数独1的方法进行就好了..数独1没写题解吧...这里补下QAQ.
1.首先观察计数,我们观察层数会发现,假如我们下标从0开始,那么在我们填一个数(x,y)时,付出的代价是min(min(8-x,x),min(8-y,y))+6;那么假设我们填的数是val,那么得分就是val*min(min(8-x,x),min(8-y,y))+6;
2.和数独1一样,我们可以预先处理出两个数组,一个ones,一个mp.第一个判断二进制数中有几个1,第二个用来判断一个二进制数是2的几次方.为什么要这两个预处理呢?第一个ones我们是用来,在对于每次选择分支少的进行剪枝的,第二个mp枚举可填位子的时候填哪个数.
3.先记录下有多少空是空的的,我们优先填空中选择最少的空,这样搜索的分支将会更小,然后进行递归dfs即可,用个ans记录答案,一旦搜完就更新ans.
4.由于每行,每列,每个九宫格都只能出现1~9,我们用二进制数存一下每行,每列,每个九宫格使用情况.开始将他们赋值为(1<<9)-1.然后一旦一个数填了t,我们就将这个数-(1<<t).emm这就是整个过程了,下面就是看代码怎么写了QAQ
下面就是代码了:
#include <bits/stdc++.h>
using namespace std;
const int N=9;
int a[N][N],cnt=0,ans=-1,val=0,line[N],row[N],cell[N][N];
int ones[1<<9],mp[1<<9];
inline int get(int x,int y,int z)//填哪个数,然后算出来的价值
{
return z*(min(min(8-x,x),min(8-y,y))+6);
}
inline int lowbit(int x)//在可选集合,一个一个数的填.
{
return x&(-x);
}
void draw(int x,int y,int t)//在x,y中填t.
{
a[x][y]=t;
row[x]-=(1<<(t-1));
line[y]-=(1<<(t-1));
cell[x/3][y/3]-=(1<<(t-1));
}
inline int f(int x,int y)
{
return cell[x/3][y/3]&row[x]&line[y];//算出可以填的位子
}
void dfs(int cnt,int val)//dfs填了所有数,然后更新ans
{
if(cnt==0) {if(val>ans) ans=val;return;}//递归出口.
int vv=10;//先赋值最大可以填的.
int x,y;//记录坐标.
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(ones[f(i,j)]<vv&&!a[i][j])
{
vv=ones[f(i,j)];
x=i,y=j;
}
}
}//找到分支最小的点.
//cout<<x<<' '<<y<<' '<<endl;
for(int i=f(x,y);i;i-=(lowbit(i)))
{
int t=mp[lowbit(i)]+1;
draw(x,y,t);
dfs(cnt-1,val+get(x,y,t));
row[x]+=(1<<(t-1));
line[y]+=(1<<(t-1));
cell[x/3][y/3]+=(1<<(t-1));
a[x][y]=0;
}
}
void init()
{
for(int i=0;i<N;i++) row[i]=line[i]=(1<<9)-1;
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
cell[i][j]=(1<<9)-1;
}
}
for(int i=0;i<N;i++) mp[1<<i]=i;
for(int i=0;i<(1<<N);i++)
{
for(int j=i;j;j-=lowbit(j)) ones[i]++;
}
}
int main()
{
init();
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
cin>>a[i][j];
if(a[i][j])
{
draw(i,j,a[i][j]);
val+=get(i,j,a[i][j]);
}
else cnt++;
}
}
dfs(cnt,val);//n个点需要填,现在当前的价值是val了.
cout<<ans<<endl;
return 0;
}感谢辛格大佬QAQ,又出bug了

京公网安备 11010502036488号