P1074 靶形数独 (DFS)

题目链接

题面:
在这里插入图片描述

题解:
与正常的数独一样,不过这个并不是跑出一个解来即可,需要所有解取最大值。
既然是最大值,那么肯定可以最优性剪枝,不过不剪也能过,就没剪。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[10][10];
int row[9],col[9],grid[9],cnt[512],num[512],tot;
int maxx=-1;
const int c[10][10]=
{
    {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}
};



int g(int x, int y)//得到九宫格的哪一个
{
	return ((x/3)*3)+(y/3);
}

inline void flip(int x, int y, int z) //更新当前状态和还原现场
{
	row[x]^=1<<z;
	col[y]^=1<<z;
	grid[g(x, y)]^=1<<z;
}

void dfs(int now,int ans)
{
	if (now==0) //填完了
    {
        maxx=max(maxx,ans);
        return ;
    }

	int temp=10,x,y;

	for (int i=0;i<9;i++)
		for (int j=0;j<9;j++)
        {
			if(a[i][j]!= 0) continue;
			int val=row[i]&col[j]&grid[g(i, j)];//能填的数
			if(!val) return ;//没有能填的数
			if(cnt[val]<temp) //当前位置能填的数的个数
			{
				temp=cnt[val];
				x=i,y=j;
			}
		}

	int val=row[x]&col[y]&grid[g(x, y)];//得到能填的数
	for( ;val;val-=val&-val)
    {
		int z=num[val&-val];//第几位
        a[x][y]=1+z;//更新当前状态
		flip(x,y,z);

		dfs(now-1,ans+c[x][y]*a[x][y]);

		flip(x,y,z);//还原现场
		a[x][y] = 0;
	}
	return ;
}

int main()
{
	for(int i=0;i<(1<<9);i++)//预处理i状态1的个数
		for(int j=i;j;j-=j&-j) cnt[i]++;
	for (int i=0;i<9;i++)//预处理第几位
		num[1<<i] = i;

    for(int i=0;i<9;i++)
        for(int j=0;j<9;j++)
            scanf("%d",&a[i][j]);


    for (int i=0;i<9;i++) //全部初始化为可填。
        row[i]=col[i]=grid[i]=(1 << 9)-1;

    tot=0;//需要填的个数
    int ans=0;
    for(int i=0;i<9;i++)
        for (int j=0;j<9;j++)
            if (a[i][j] != 0) flip(i,j,a[i][j]-1),ans+=a[i][j]*c[i][j];//把行列九宫格不能填的去掉。
            else tot++;

    dfs(tot,ans);

    printf("%d\n",maxx);

	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值