HDU 1426 Sudoku Killer (回溯 + 剪枝)

题意:

  给你一个 9*9 的矩阵,同一行相邻的两个元素用一个空格分开。其中1-9代表该位置的已经填好的数,问号(?)表示需要你填的数。输出这个数独的解,每组有且只有一个解。

思路:

  记录下空缺的地方,每个空缺的地方有 9 中状态,DFS + 剪枝处理其他的,用scanf进行输入,gets() TLE到死。。。。

代码:

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

const int MAXN = 11;
int Gra[MAXN][MAXN];//存放 9 * 9 的大格局
int Ans[83];     //存放 空缺的、要填数的 位置的 一种映射 (i - 1 ) * 9 + j
int rowLine[11][11]; //rowLine[ z =  (i - 1) / 3 * 3 + (j - 1) / 3  ][k]表示 第 z(0 1 2 3 4 5 6 7 8) 个格子中 k 数字是否出现过(0 / 1)
int line[11][11];   // line[i][k] 表示 第 i 行 k 这个数字是否出现过
int row[11][11];    //row[j][k]  表示 第 j  列 k 这个数字是否出现过
int N;              //要填数的格子的总数

int getX(int k)                     //根据存放空缺位置的数组的第k个数反推出坐标 X
{
    return (Ans[k] - 1) / 9 + 1;
}
int getY(int k)             //根据存放空缺位置的数组的第k个数反推出坐标 Y
{
    return Ans[k] % 9 == 0 ? 9 : Ans[k] % 9;
}

void deal(int i, int j, int k, int num)  //在 Gra(i, j)位置 放k(num = 1)/移走k(num = -1) 时需要维护用于标记是否重复的数组
{
    line[i][ k ] += num;             //维护行数组
    row[j][ k ] += num;             //维护列数组
    rowLine[(i - 1) / 3 * 3 + (j - 1) / 3 ][k] += num;  //维护 标记 3 * 3 的数组
}

int check(int k, int n)  //判断在 第 n 个空缺的地方放置 k 是否合法
{
    int x = getX(n);
    int y = getY(n);
    if(line[x][k] == 1) return 0;   //同一行有重复的
    if(row[y][k] == 1) return 0;        //同一列有重复的
    if(rowLine[ (x - 1) / 3 * 3 + (y - 1) / 3 ][k] == 1) return 0;  //同一个 3 * 3的方格子里有重复的
    return 1;
}

void pf()
{
    for(int i = 1; i <= 9; i++)
    {
        for(int j = 1; j <= 9; j++)
            printf(j == 1 ? "%d":" %d",Gra[i][j]);
        cout <<endl;
    }
}

int flag;
void backtrack(int k)
{
    if( k > N ){pf();flag = 1;return;}
    for(int i = 1; i <= 9; i++) //每一个 空缺的位置都有 9 种填法(状态)
    {
        int x = getX(k);int y = getY(k);
        if(check(i, k))  //判断合法性
        {
            Gra[ x ][ y ] = i;
            deal(x, y, i, 1);    //由于新加入的数 所以需要维护 标志的数组
            backtrack( k + 1);
            //if(flag )return;
            deal(x, y, i, -1);  //恢复现场
            Gra[ x ][ y ] = 0;
        }
    }
}

//初始化
void init()
{
    N = 0;
    flag = 0;
    memset(Gra, -1, sizeof(Gra));
    memset(rowLine, 0, sizeof(rowLine));
    memset(Ans, 0, sizeof(Ans));
    memset(line, 0, sizeof(line));
    memset(row, 0, sizeof(row));
}

int main()
{

    //freopen("in.txt", "r", stdin);
    char s[3];
    int ln = 0;
    while(~scanf("%s",s))
    {
        if(ln++)printf("\n");
        init();
        if(s[0] == ‘?‘){Gra[1][1] = 0; Ans[++N] = 1;}
        else{ Gra[1][1] = s[0] - 48;   deal(1 , 1, Gra[1][1], 1);}
        for(int i = 0; i < 9; i++)
        {
            for(int j = 0; j < 9; j++)
            {
                if(i == 0 &&  j == 0)continue;
                scanf("%s",s);
                if(s[0] == ‘?‘){Gra[i + 1][j + 1] = 0; Ans[++N] = i * 9 + j + 1;}
                else{ Gra[i + 1][j + 1] = s[0] - 48;   deal(i + 1 , j + 1, Gra[i + 1][j + 1], 1);}
            }
        }
        flag = 0;
        backtrack(1);
    }
    return 0;
}
时间: 2024-10-09 20:14:49

HDU 1426 Sudoku Killer (回溯 + 剪枝)的相关文章

HDU 1426 Sudoku Killer(dfs 解数独)

传送门: http://acm.hdu.edu.cn/showproblem.php?pid=1426 Sudoku Killer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9804    Accepted Submission(s): 2944 Problem Description 自从2006年3月10日至11日的首届数独世界

HDU 1426 Sudoku Killer(数独,划分区域是关键)

Sudoku Killer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6283    Accepted Submission(s): 1981 Problem Description 自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视. 据说,在2008北京奥运会上,会将数独列为一个单

hdu 1426 Sudoku Killer

题目:http://acm.hdu.edu.cn/showproblem.php?pid=1426 1 #include<stdio.h> 2 #include<math.h> 3 #include<string.h> 4 #include<stdlib.h> 5 #include<iostream> 6 using namespace std; 7 char map[12][12]; 8 bool row[12][12],list[12][12

HDU 1426 Sudoku Killer【DFS 数独】

自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视. 据说,在2008北京奥运会上,会将数独列为一个单独的项目进行比赛,冠军将有可能获得的一份巨大的奖品———HDU免费七日游外加lcy亲笔签名以及同hdu acm team合影留念的机会. 所以全球人民前仆后继,为了奖品日夜训练茶饭不思.当然也包括初学者linle,不过他太笨了又没有多少耐性,只能做做最最基本的数独题,不过他还是想得到那些奖品,你能帮帮他吗?你只要把答案告诉他就可以,不用教他是怎么做的

HDU 1426 Sudoku Killer DFS 简单题

给出一个数独的一部分,然后然后要我们填完整这个数独. Input 本题包含多组测试,每组之间由一个空行隔开.每组测试会给你一个 9*9 的矩阵,同一行相邻的两个元素用一个空格分开.其中1-9代表该位置的已经填好的数,问号(?)表示需要你填的数. Output 对于每组测试,请输出它的解,同一行相邻的两个数用一个空格分开.两组解之间要一个空行.对于每组测试数据保证它有且只有一个解. Sample Input 7 1 2 ? 6 ? 3 5 8 ? 6 5 2 ? 7 1 ? 4 ? ? 8 5 1

hdu 1426 Sudoku Killer ( Dancing Link 精确覆盖 )

利用 Dancing Link 来解数独 具体的可以看    lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , 是通过求解精确覆盖 精确覆盖就是给出一个 01 矩阵 , 要求我们选择一些行 , 使得每一列有且仅有一个 1 对于数独问题 , 行就是我们的选择 , 即在第 i 行 第 j 列 放上 数字 k , 所以我们最多有 i * j * k 中选择 如果某些位置( x , y  )已经放了数字 a , 那么我们的选择

hdu 1426 Sudoku Killer(DFS)

1 #include <iostream> 2 #include <memory.h> 3 #include <vector> 4 #include <string> 5 #include <cstdio> 6 using namespace std; 7 8 int row[11][11],col[11][11],blo[11][11],mp[11][11]; 9 struct node{ 10 int x,y; 11 }; 12 node u

HUD 1426 Sudoku Killer (DFS)

链接 : Here! 思路 : 记录下所有 "?" , 出现的位置, 然后 $DFS$ 一下, 对于每个位置来说都可以填充 $9$ 种数值, 然后对于判断填充是否合法需要三个标记数组来辅助记录. $visR[i][num] = 1, 代表第 i 行num值已经出现过, visC[i][num] = 1, 代表第 i 列num值已经出现过, visB[i][num] = 1, 代表第 i 小块 num值已经出现过$. 计算小块的标号只需要 $x / 3 * 3 + y / 3 $ 即可.

Sudoku Killer

Sudoku Killer Time Limit: 1000ms                                                   Memory Limit: 32768KB 64-bit integer IO format:      Java class name: 自从2006年3月10日至11日的首届数独世界锦标赛以后,数独这项游戏越来越受到人们的喜爱和重视.据说,在2008北京奥运会上,会将数独列为一个单独的项目进行比赛,冠军将有可能获得的一份巨大的奖