acm之旅之数独问题

文章目录

Sudoku

题目链接:Sudoku
参考博文:数独问题的介绍及POJ 2676-Sudoku(dfs+剪枝)

  • 题目大意:
    给你一个数独,让你填数:
    1.每行的九个数字互不相同;
    2.每列的九个数字各不相同;
    3.被分成的3*3的小矩阵中的九个数字互不相同;
    输出完成后的数表,若不能满足上述条件,则输出原图。
  • 思路:这道题大致思路比较好想,但是一直想不到优雅的实现方式,看了上面的博文后,发现了二维数组的用法,典型的用空间换时间。
    本道题的重点是三个二维数组的定义
    • row[i][x]表示第i行中x数字是否已经出现(0/1)。
    • col[j][x]表示第j列中x数字是否已经出现(0/1)。
    • s[k][x]表示第k个 3 × 3 3\times 3 3×3的小正方形中x数字是否已经出现。
      其中 k = 3 × ( ( i − 1 ) / 3 ) + ( j − 1 ) / 3 + 1 k=3\times ((i-1)/3)+(j-1)/3+1 k=3×((i1)/3)+(j1)/3+1。(i,j)为该元素的下标。

之后就可以使用dfs来回溯暴力枚举。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

string str;
int m[10][10], row[10][10], col[10][10], s[10][10];
void Init()
{
    memset(row, 0, sizeof(row));
    memset(col, 0, sizeof(col));
    memset(s, 0, sizeof(s));
}
int get_k(int i, int j)
{
    return 3*((i-1)/3)+(j-1)/3+1;
}
int dfs(int x, int y)
{
    if(x==10) return 1;
    int flag = 0, k = get_k(x, y);
    if(m[x][y])//当该位置不需要填值时
    {
        if(y==9)
            flag = dfs(x+1, 1);
        else
            flag = dfs(x, y+1);
        if(flag) return 1;
        else     return 0;
    }
    else
    {
        for(int i=1; i<=9; i++)//暴力枚举数字
        {
            if(!row[x][i] && !col[y][i] && !s[k][i])//表明该数字可以填
            {
                row[x][i] = 1, col[y][i] = 1, s[k][i] = 1, m[x][y] = i;
                if(y==9)
                    flag = dfs(x+1, 1);
                else
                    flag = dfs(x, y+1);
                if(flag)
                    return 1;
                else//不要忘记将数据还原
                    row[x][i] = 0, col[y][i] = 0, s[k][i] = 0, m[x][y] = 0;
            }
        }
    }
    return 0;
}
int main()
{
    int T;
    cin >> T;
    getchar();
    while(T--)
    {
        Init();
        //边输入边标记
        for(int i=1; i<=9; i++)
        {
            getline(cin, str);
            str = " "+str;
            for(int j=1; j<=9; j++)
            {
                m[i][j] = str[j]-'0';
                if(m[i][j])
                {
                    int k = get_k(i, j);
                    row[i][m[i][j]] = 1;
                    col[j][m[i][j]] = 1;
                    s[k][m[i][j]] = 1;
                }
            }
        }
        dfs(1, 1);
        for(int i=1; i<=9; i++)
        {
            for(int j=1; j<=9; j++)
            {
                printf("%d", m[i][j]);
            }
            printf("\n");
        }
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值