AcWing 169. 数独2(复杂的搜索+剪枝)

2024-04-15 23:08

本文主要是介绍AcWing 169. 数独2(复杂的搜索+剪枝),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

思路:

  • 可以看出来,这就是数独加强版, 9 ∗ 9 9*9 99变成了 16 ∗ 16 16*16 1616。对应的算法效率要求也更高。一开始想在 9 ∗ 9 9*9 99的代码上加剪枝水过去,搜索功力还是不足过不去。。。
  • 参考了《进阶指南》的思路和代码。
  • 思路就是搜索的时候遍历每个点,如果这个点不能选数了,那么剪掉,如果只能选一个数,那就选上。(这里以及下面所有“点”都是针对空格点)
  • 遍历每一行,如果这一行没数可选那就剪掉,如果只能选一个数那就选上。列和每个4*4小块同理。
  • 最后再按照常规思路,遍历每个格子选出可选数最少的格子从这里开始枚举选哪个数搜索下去。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
char s[16][16];
int cnt[1 << 16],f[1 << 16],num[16][16];
vector<int>e[1 << 16];
void work(int i,int j,int k) {for(int t = 0;t < 16;t++) {num[i][t] &= ~(1 << k);num[t][j] &= ~(1 << k);}int x = i / 4 * 4,y = j / 4 * 4;for(int ti = 0;ti < 4;ti++) {for(int tj = 0;tj < 4;tj++) {num[x + ti][y + tj] &= ~(1 << k);}}
}
bool dfs(int ans) {if(!ans) return true;int pre[16][16];memcpy(pre,num,sizeof(num));//遍历所有格子for(int i = 0;i < 16;i++) {for(int j = 0;j < 16;j++) {if(s[i][j] == '-') {if(!num[i][j]) return false; //有格子选不了直接剪掉if(cnt[num[i][j]] == 1) { //只能选这一个数,选上s[i][j] = f[num[i][j]] + 'A';work(i,j,f[num[i][j]]);if(dfs(ans - 1)) return true;s[i][j] = '-';memcpy(num,pre,sizeof(num));return false;}}}}//遍历每一行for(int i = 0;i < 16;i++) {int w[16],o = 0;memset(w,0,sizeof(w));for(int j = 0;j < 16;j++) {if(s[i][j] == '-') {o |= num[i][j];for(int k = 0;k < e[num[i][j]].size();k++) {++w[e[num[i][j]][k]];}} else {o |= (1 << (s[i][j] - 'A'));w[f[1<<(s[i][j] - 'A')]] = -1;}}if(o != (1 << 16) - 1) return false;for(int k = 0;k < 16;k++) {if(w[k] == 1) {for(int j = 0;j < 16;j++) {if(s[i][j] == '-' && ((num[i][j] >> k) & 1)) {s[i][j] = k + 'A';work(i,j,k);if(dfs(ans - 1)) return true;s[i][j] = '-';memcpy(num,pre,sizeof(num));return false;}}}}}//遍历每一列for(int j = 0;j < 16;j++) {int w[16],o = 0;memset(w,0,sizeof(w));for(int i = 0;i < 16;i++) {if(s[i][j] == '-') {o |= num[i][j];for(int k = 0;k < e[num[i][j]].size();k++) {++w[e[num[i][j]][k]];}} else {o |= (1 << (s[i][j] - 'A'));w[f[1<<(s[i][j] - 'A')]] = -1;}}if(o != (1 << 16) - 1) return false;for(int k = 0;k < 16;k++) {if(w[k] == 1) {for(int i = 0;i < 16;i++) {if(s[i][j] == '-' && ((num[i][j] >> k) & 1)) {s[i][j] = k + 'A';work(i,j,k);if(dfs(ans - 1)) return true;s[i][j] = '-';memcpy(num,pre,sizeof(num));return false;}}}}}//遍历每一个4*4小块for(int i = 0;i < 16;i += 4) {for(int j = 0;j < 16;j += 4) {int w[16],o = 0;memset(w,0,sizeof(w));for(int p = 0;p < 4;p++) {for(int q = 0;q < 4;q++) {if(s[i + p][j + q] == '-') {o |= num[i + p][j + q];for(int k = 0;k < e[num[i + p][j + q]].size();k++) {++w[e[num[i + p][j + q]][k]];}} else {o |= (1 << (s[i + p][j + q] - 'A'));w[f[1 << (s[i + p][j + q] - 'A')]] = -1;}}}if(o != (1 << 16) - 1) return false;for(int k = 0;k < 16;k++) {if(w[k] == 1) {for(int p = 0;p < 4;p++) {for(int q = 0;q < 4;q++) {if(s[i + p][j + q] == '-' && ((num[i + p][j + q] >> k) & 1)) {s[i + p][j + q] = k + 'A';work(i + p,j + q,k);if(dfs(ans - 1)) return true;s[i + p][j + q] = '-';memcpy(num,pre,sizeof(num));return false;}}}}}}}//选择可选数最少的那个格子int k = 17,tx,ty;for(int i = 0;i < 16;i++) {for(int j = 0;j < 16;j++) {if(s[i][j] == '-' && cnt[num[i][j]] < k) {k = cnt[num[i][j]];tx = i;ty = j;}}}for(int i = 0;i < e[num[tx][ty]].size();i++) {int tz = e[num[tx][ty]][i];work(tx,ty,tz);s[tx][ty] = tz + 'A';if(dfs(ans - 1)) return true;s[tx][ty] = '-';memcpy(num,pre,sizeof(num));}return false;
}
void solve() {for(int i = 1;i < 16;i++) scanf("%s",s[i]);for(int i = 0;i < 16;i++) {for(int j = 0;j < 16;j++) {num[i][j] = (1 << 16) - 1;}}int ans = 0;for(int i = 0;i < 16;i++) {for(int j = 0;j < 16;j++) {if(s[i][j] != '-') {work(i,j,s[i][j] - 'A');} else {ans++;}}}if(dfs(ans)) {for(int i = 0;i < 16;i++) {for(int j = 0;j < 16;j++) {printf("%c",s[i][j]);}printf("\n");}} else {printf("DEBUG\n");}printf("\n");
}
int get_cnt(int i) {int k = i & -i;e[i].push_back(f[k]);for(int j = 0;j < e[i - k].size();j++) {e[i].push_back(e[i - k][j]);}return cnt[i - k] + 1;
}
void init() {for(int i = 0;i < 16;i++) f[1 << i] = i;cnt[0] = 0;for(int i = 1;i < (1 << 16);i++) {cnt[i] = get_cnt(i);}
}
int main() {init();while(~scanf("%s",s[0])) {solve();}return 0;
}

这篇关于AcWing 169. 数独2(复杂的搜索+剪枝)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/907186

相关文章

认识、理解、分类——acm之搜索

普通搜索方法有两种:1、广度优先搜索;2、深度优先搜索; 更多搜索方法: 3、双向广度优先搜索; 4、启发式搜索(包括A*算法等); 搜索通常会用到的知识点:状态压缩(位压缩,利用hash思想压缩)。

hdu1240、hdu1253(三维搜索题)

1、从后往前输入,(x,y,z); 2、从下往上输入,(y , z, x); 3、从左往右输入,(z,x,y); hdu1240代码如下: #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#inc

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

hdu 4517 floyd+记忆化搜索

题意: 有n(100)个景点,m(1000)条路,时间限制为t(300),起点s,终点e。 访问每个景点需要时间cost_i,每个景点的访问价值为value_i。 点与点之间行走需要花费的时间为g[ i ] [ j ] 。注意点间可能有多条边。 走到一个点时可以选择访问或者不访问,并且当前点的访问价值应该严格大于前一个访问的点。 现在求,从起点出发,到达终点,在时间限制内,能得到的最大

AI基础 L9 Local Search II 局部搜索

Local Beam search 对于当前的所有k个状态,生成它们的所有可能后继状态。 检查生成的后继状态中是否有任何状态是解决方案。 如果所有后继状态都不是解决方案,则从所有后继状态中选择k个最佳状态。 当达到预设的迭代次数或满足某个终止条件时,算法停止。 — Choose k successors randomly, biased towards good ones — Close

hdu4277搜索

给你n个有长度的线段,问如果用上所有的线段来拼1个三角形,最多能拼出多少种不同的? import java.io.BufferedInputStream;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;

hdu1010 奇偶剪枝

恰好t时间到达 import java.io.BufferedReader;import java.io.InputStream;import java.io.InputStreamReader;import java.io.PrintWriter;import java.math.BigInteger;import java.util.Arrays;import

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

浙大数据结构:04-树7 二叉搜索树的操作集

这道题答案都在PPT上,所以先学会再写的话并不难。 1、BinTree Insert( BinTree BST, ElementType X ) 递归实现,小就进左子树,大就进右子树。 为空就新建结点插入。 BinTree Insert( BinTree BST, ElementType X ){if(!BST){BST=(BinTree)malloc(sizeof(struct TNo

最近心情有点复杂:论心态

一月一次的彷徨又占据了整个身心;彷徨源至不自信;而不自信则是感觉自己的价值没有很好的实现亦或者说是自己不认可自己的目前的生活和状态吧。 我始终相信一句话:任何人的生活形态完全是由自己决定的;外在的总归不能直达一个人的内心深处。所以少年 为了自己想要的生活 多坚持努力吧、不为别人只为自己心中的那一丝执着。 由此我看到了一个故事: 一个心情烦躁的人去拜访禅师。他问禅师:我这辈子就这么注定了吗?您