洛谷—P1074 靶形数独题解

本文介绍了洛谷P1074靶形数独的解题思路,类似于八皇后问题,但需要处理更多状态。通过记录每行空白格数量并排序进行剪枝,使用三维数组记录数字填充状态,以实现高效搜索。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: P1074 靶形数独
题目大意: 在99的方格填数,要求每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。求最大分数。
题解思路: 这道题和八皇后的思路差不多。只是要判断的状态多一些。我们首先先一个问题,我们拿到这个9
9宫格就开始搜索吗?有没有可能处理一下这个9*9宫格可以剪枝?想一下我们要填的是空白方格,如果行要填的空白方格越少那么搜索的层数就越少,搜索花的时间就越少。我们可以建一个结构体

struct Row
{
    int zeroNum, lineIndex;//0的个数和行的编号
}row[10];

记录每一行的空白空格的数量然后排序即可。然后我们可以建一个三维数组记录这一行或这一列或这一九宫格中这个数有没有填过。
代码:

vis[1][x][v]:标记行是x,数字是v;
vis[2][y][v]:标记列是y,数字是v;
vis[3][g][v]:标记小九宫格序号是g,数字是v;
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 100;
int map[maxn][maxn], vis[4][maxn][maxn],result,b[maxn],a[maxn][maxn];
int ans=0,flag=0;
struct Row
{
    int zeroNum, lineIndex;
}row[10];
bool cmp(Row a, Row b) {
    return a.zeroNum < b.zeroNum;
}
int which(int i, int j)
{
    if (i <= 3)
    {
        if (j <= 3)        return 1;
        else if (j <= 6)   return 2;
        else            return 3;
    }
    else if (i <= 6)
    {
        if (j <= 3)        return 4;
        else if (j <= 6)    return 5;
        else            return 6;
    }
    else
    {
        if (j <= 3)        return 7;
        else if (j <= 6)   return 8;
        else            return 9;
    }
}

int point(int i, int j)
{
    if (i == 1 || j == 1 || i == 9 || j == 9)   return 6;
    if (i == 2 || j == 2 || i == 8 || j == 8)     return 7;
    if (i == 3 || j == 3 || i == 7 || j == 7)   return 8;
    if (i == 4 || j == 4 || i == 6 || j == 6)   return 9;
    return 10;
}
void DFS(int count, int sum) {
    if (count == 82) {//所有的空格填完
        flag = 1;
        result = max(result, sum);
        return;
    }
    int x = b[count] / 9 + 1;
    int y = b[count] % 9;
    if (y == 0) {//y=0说明搜索到列数为9的方格,改变x和y的值。
        x = b[count] / 9;
        y = 9;
    }
    if (!map[x][y]) {
        for (int i = 1; i <= 9; i++) {
            int g = which(x, y);
            if (!vis[1][x][i] && !vis[2][y][i] && !vis[3][g][i]) {
                vis[1][x][i] = vis[2][y][i] = vis[3][g][i] = 1;//标记
                DFS(count + 1, sum + i*point(x,y));
                vis[1][x][i] = vis[2][y][i] = vis[3][g][i] = 0;//回溯
            }
        }
    }
    else {
        DFS(count + 1, sum);
    }
}
int main() {
	for (int i = 1; i <= 9; i++) {
		for (int j = 1; j <= 9; j++) {
			cin >> map[i][j];
			if (map[i][j] == 0) {
                row[i].zeroNum++;
                row[i].lineIndex = i;
            }
            else {
                vis[1][i][map[i][j]] = vis[2][j][map[i][j]] = vis[3][which(i, j)][map[i][j]] = 1;
            }
			ans += map[i][j]*point(i,j);//计算起始的分数
		}
	}
    int num = 0;
    sort(row + 1, row + 1 + 9, cmp);//排序
    for (int i = 1; i <= 9; i++) {
        for (int j = 1; j <= 9; j++) {
            int x = row[i].lineIndex;
            int y = j;
            b[++num] = (x - 1) * 9 + y;//将排序后的点放入一维数组中
        }
    }
    DFS(1, ans);
    if (flag) {
        cout << result << endl;
    }
    else {
        cout << -1 << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值