数独--暴力、剪枝搜索

import java.util.Scanner;
public class Main {
    static int arr[][];
    static Scanner in = new Scanner(System.in);
    public static void main(String[] args) {
        arr = new int[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                arr[i][j] = in.nextInt();
            }
        }
        dfs(0);
    }
    private static void dfs(int index) {
        if (index == 81) {
            for (int i = 0; i < 9; i++) {
                for (int j = 0; j < 9; j++) {
                    System.out.print(arr[i][j] + " ");
                }
                System.out.println();
            }
            return;
        }
        int row = index / 9;
        int col = index % 9;
        if (arr[row][col] == 0) {
            for (int i = 1; i <= 9; i++) {
                if (valid(i, row, col)) {
                    arr[row][col] = i;
                    dfs(index + 1);
                    arr[row][col] = 0;
                }
            }
        } else
            dfs(index + 1);
    }
    private static boolean valid(int num, int raw, int col) {
        for (int i = 0; i < 9; i++) {
            if ( arr[raw][i] == num||arr[i][col] == num) {
                return false;
            }
        }
        int tmpx = raw / 3;
        int tmpy = col / 3;
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (arr[tmpx * 3 + i][tmpy * 3 + j] == num)
                    return false;
            }
        }
        return true;
    }
}


https://www.bilibili.com/video/av53554818

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 9;
int ones[1 << N], map[1 << N];                //ones 表示 x 里面有几个1;//小抄 map表示 一个数最右边的1以及跟剩下的0组成后 为第几位
int row[N], col[N], cell[3][3];
char str[100];
inline int lowbit(int x)                    //lowbit 计算最低位!!!
{
    return x & -x;
}
void init()                                ////全部赋值位111111111 表示1~9个数都可以选择 简化后面的与运算
{
    for (int i = 0; i < N; i ++ ) row[i] = col[i] = (1 << N) - 1;
    for (int i = 0; i < 3; i ++ )
        for (int j = 0; j < 3; j ++ )
            cell[i][j] = (1 << N) - 1;
}
// 求可选方案的交集
inline int get(int x, int y)            ////进行与运算 表示真正可以选哪些数
{
    return row[x] & col[y] & cell[x / 3][y / 3];
}
bool dfs(int cnt)
{
    if (!cnt) return true;
    // 找出可选方案数最少的空格
    int minv = 10;
    int x, y;
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            if (str[i * 9 + j] == ‘.‘)
            {
                int t = ones[get(i, j)];
                if (t < minv)
                {
                    minv = t;
                    x = i, y = j;
                }
            }
    for (int i = get(x, y); i; i -= lowbit(i))
    {
        int t = map[lowbit(i)];
        // 修改状态
        row[x] -= 1 << t;
        col[y] -= 1 << t;
        cell[x / 3][y / 3] -= 1 << t;
        str[x * 9 + y] = ‘1‘ + t;
        if (dfs(cnt - 1)) return true;
        // 恢复现场
        row[x] += 1 << t;
        col[y] += 1 << t;
        cell[x / 3][y / 3] += 1 << t;
        str[x * 9 + y] = ‘.‘;
    }
}
int main()
{
    for (int i = 0; i < N; i ++ ) map[1 << i] = i;
    for (int i = 0; i < 1 << N; i ++ )
    {
        int s = 0;
        for (int j = i; j; j -= lowbit(j)) s ++ ;
        ones[i] = s; // i的二进制表示中有s个1
    }
    while (cin >> str, str[0] != ‘e‘)
    {
        init();
        int cnt = 0;
        for (int i = 0, k = 0; i < N; i ++ )
            for (int j = 0; j < N; j ++ , k ++ )
                if (str[k] != ‘.‘)
                {
                    int t = str[k] - ‘1‘;
                    row[i] -= 1 << t;
                    col[j] -= 1 << t;
                    cell[i / 3][j / 3] -= 1 << t;
                }
                else cnt ++ ;
        dfs(cnt);
        cout << str << endl;
    }
    return 0;
}

原文地址:https://blog.51cto.com/14429166/2416831

时间: 2024-10-21 15:01:35

数独--暴力、剪枝搜索的相关文章

HDU 4876 ZCC loves cards(暴力剪枝)

HDU 4876 ZCC loves cards 题目链接 题意:给定一些卡片,每个卡片上有数字,现在选k个卡片,绕成一个环,每次可以再这个环上连续选1 - k张卡片,得到他们的异或和的数,给定一个L,问能组成[L,R]所有数字的情况下,R的最大值是多少 思路:暴力C(20, 6),然后对于每个序列去全排后模拟计算值, 不过之前要有个剪枝,全排前,先把k个数随机取数(即不用连续),然后如果这样还满足不了,那么连续的情况肯定也满足不了,直接结束,不进入全排.这样一来由于满足不了的情况实际上是占绝大

uva10245 - The Closest Pair Problem(暴力+剪枝)

题目:uva10245 - The Closest Pair Problem(暴力+剪枝) 题目大意:给出N个点,求这些点中最小的两点距离. 解题思路:把这些点中两两之间的距离都算出来,这样的复杂度是O(n^2),会超时,所以加了一个减枝. 先将所有的点按照x坐标排序.然后在计算的过程中,如果发现要计算的这两点的X坐标之差的绝对值已经大于等于当前的最小值,那么说明后面的点计算距离一定比这个最小值要大. 这题的正解貌似是分治法,可惜没看懂. 代码: #include <stdio.h> #inc

hdu 4876 暴力剪枝

hdu 4876 终于过了, 之前写的代码虽然思路是这样的但是有好多可以优化的地方没有注意所以一直超时超时超时!,学习了一下别人的代码,虽然看上去没什么差别但实际上却可以节省很多时间,恩恩又学到了一些技巧~     ^_^ . [题意]:给定一些卡片,每个卡片上有数字,现在选k个卡片,绕成一个环,每次可以再这个环上连续选1 - k张卡片,得到他们的异或和的数,给定一个L,问能组成[L,R]所有数字的情况下,R的最大值是多少. [思路]:暴力+剪枝  枚举在m个数里选k个数的 C(m,k)种情况,

剪枝搜索

剪枝搜索是搜索中常用的一个方法,Binary Search就是一个经典的剪枝搜索例子,在Biniary Search中 int binarySearch(int A[], int low, int high, int key) { int mid; while (low <= high) { mid = (low + high) >> 1; if (key < A[mid]) high = mid - 1; else if (key > A[mid]) low = mid +

朴素搜索dfs, 简单的剪枝搜索

为做一个项目选择最合适的语言固然重要,但是,掌握一门自己熟练的兵器,也很重要. ===================================================================================================================== 继续总结搜索类的题目,这一类的题目,目前仅分析简单粗暴的dfs搜索,以及简单的剪枝. 参考的题目: http://acm.hdu.edu.cn/showproblem.php?pid=

POJ 3134 Power Calculus (迭代剪枝搜索)

题目大意:略 题目里所有的运算都是幂运算,所以转化成指数的加减 由于搜索层数不会超过$2*log$层,所以用一个栈存储哪些数已经被组合出来了,不必暴力枚举哪些数已经被搜出来了 然后跑$iddfs$就行了 可以加一个剪枝,设你选择的最大迭代深度为K,现在如果当前组合出的数$x$,满足$x*2^{K-dep}<n$,说明$n$一定无法被$x$组合出来(即自己不断加自己),$x$对于答案是一定无意义的,就跳出 1 #include <queue> 2 #include <cstdio&g

HDU 5839 Special Tetrahedron (2016CCPC网络赛08) (暴力+剪枝)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5839 在一个三维坐标,给你n个点,问你有多少个四面体(4个点,6条边) 且满足至少四边相等 其余两边不相邻. 暴力4重循环,但是在第3重循环的时候需要判断是否是等腰三角形,这便是一个剪枝.在第4重循环的时候判断4点是否共面 (叉乘), 5或者6边相等就+1,4边相等就判断另外两边是否相交就行了. 赛后过的,觉得自己还是太菜了. 1 //#pragma comment(linker, "/STACK:

uva 10245 The Closest Pair Problem (暴力+剪枝)

uva 10245 The Closest Pair Problem 题目大意:给出n个点,求出距离最近的两点间的距离.若点与点间的距离都大于10000,输出INFINITY 解题思路:这题的正统做法是分治,偷懒方法是暴力加剪枝.先按x坐标排序,然后fabs(p[i] - p[j]) > ans的点就可以直接跳过了. #include<stdio.h> #include<string.h> #include<stdlib.h> #include<algori

【暴力剪枝】NOIP2015-斗地主[NOIP填坑]

[题目大意] 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响.每一局游戏中,一副手牌由n张牌组成.游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利.现在,牛牛只想知道,对于自己的若