题意 :给定数独的某些初始值,规定每个格子的得分,求得分最大的数独的解。

思路:这是某年的noip的原题,高中时就写过,位运算也就是那个时候学会的--。这题明显是暴搜,但是需要注意两点,一是需要加一些常数优化,也就是位运算,一个是剪枝,填完某个数后发现某个格子无解了则换个数填,并且那些可填的数的种数少的格子尽量先填,因为这样尽可能让矛盾在靠近根的地方出现。今天粗略学了一下舞蹈链--DLX,这个算法(准确来说是一个结构)可以比较高效的解决一些精确覆盖问题,对于重复覆盖问题稍作修改也适用。用DLX写了一遍数独,发现效率比位运算略高一点,但不明显。

位运算:

 #pragma comment(linker, "/STACK:10240000,10240000")

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <map>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <ctime>
#include <cctype>
#include <set>
#include <bitset>
#include <functional>
#include <numeric>
#include <stdexcept>
#include <utility> using namespace std; #define mem0(a) memset(a, 0, sizeof(a))
#define mem_1(a) memset(a, -1, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define define_m int m = (l + r) >> 1
#define rep_up0(a, b) for (int a = 0; a < (b); a++)
#define rep_up1(a, b) for (int a = 1; a <= (b); a++)
#define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)
#define rep_down1(a, b) for (int a = b; a > 0; a--)
#define all(a) (a).begin(), (a).end()
#define lowbit(x) ((x) & (-(x)))
#define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}
#define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}
#define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}
#define pchr(a) putchar(a)
#define pstr(a) printf("%s", a)
#define sstr(a) scanf("%s", a)
#define sint(a) scanf("%d", &a)
#define sint2(a, b) scanf("%d%d", &a, &b)
#define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define pint(a) printf("%d\n", a)
#define test_print1(a) cout << "var1 = " << a << endl
#define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl
#define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl typedef long long LL;
typedef pair<int, int> pii;
typedef vector<int> vi; const int dx[] = {, , -, , , , -, -};
const int dy[] = {-, , , , , -, , - };
const int maxn = 3e4 + ;
const int md = ;
const int inf = 1e9 + ;
const LL inf_L = 1e18 + ;
const double pi = acos(-1.0);
const double eps = 1e-; template<class T>T gcd(T a, T b){return b==?a:gcd(b,a%b);}
template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}
template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}
template<class T>T condition(bool f, T a, T b){return f?a:b;}
template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}
int make_id(int x, int y, int n) { return x * n + y; } int ans, a[][], f[ << ], row[], col[], block[], sp[ << ]; int getScore(int i, int j) {
return min(min(i, - i), min(j, - j)) + ;
} void init() {
rep_up0(i, ) {
f[ << i] = i;
}
} void dfs(int k, int score) {
if (k >= ) {
max_update(ans, score);
return ;
}
int x, y, c = ;
rep_up0(i, ) {
bool ok = false;
rep_up0(j, ) {
if (a[i][j]) continue;
int tmp = row[i] | col[j] | block[make_id(i / , j / , )];
int tot = 0x3fe ^ tmp;
int cnt = ;
if (tot == ) {
ok = true;
c = ;
break;
}
cnt = sp[tot];
if (cnt < c) {
x = i;
y = j;
c = cnt;
}
}
if (ok) break;
}
if (c == || c == ) return ;
int i = x, j = y;
int tmp = row[i] | col[j] | block[make_id(i / , j / , )];
int tot = 0x3fe ^ tmp;
while (tot) {
tmp = lowbit(tot);
row[i] ^= << f[tmp];
col[j] ^= << f[tmp];
block[make_id(i / , j / , )] ^= << f[tmp];
a[i][j] = f[tmp];
dfs(k + , score + f[tmp] * getScore(i, j));
row[i] ^= << f[tmp];
col[j] ^= << f[tmp];
block[make_id(i / , j / , )] ^= << f[tmp];
a[i][j] = ;
tot -= tmp;
}
} int main() {
//freopen("in.txt", "r", stdin);
sp[] = ;
rep_up1(i, << ) {
sp[i] = sp[i - lowbit(i)] + ;
}
int T;
init();
cin >> T;
while (T --) {
int sum = , cnt = , ok = true;
mem0(col);
mem0(row);
mem0(block);
rep_up0(i, ) {
rep_up0(j, ) {
sint(a[i][j]);
sum += a[i][j] * getScore(i, j);
if (a[i][j]) {
cnt ++;
if (col[j] & ( << a[i][j])) ok = false;
if (row[i] & ( << a[i][j])) ok = false;
if (block[make_id(i / , j / , )] & ( << a[i][j])) ok = false;
col[j] |= << a[i][j];
row[i] |= << a[i][j];
block[make_id(i / , j / , )] |= << a[i][j];
}
}
}
ans = -;
if (ok) dfs(cnt, sum);
cout << ans << endl;
}
}

DLX(模板):

 #pragma comment(linker, "/STACK:102400000,102400000")

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <map>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <ctime>
#include <cctype>
#include <set>
#include <bitset>
#include <functional>
#include <numeric>
#include <stdexcept>
#include <utility> using namespace std; #define mem0(a) memset(a, 0, sizeof(a))
#define mem_1(a) memset(a, -1, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define define_m int m = (l + r) >> 1
#define rep_up0(a, b) for (int a = 0; a < (b); a++)
#define rep_up1(a, b) for (int a = 1; a <= (b); a++)
#define rep_down0(a, b) for (int a = b - 1; a >= 0; a--)
#define rep_down1(a, b) for (int a = b; a > 0; a--)
#define all(a) (a).begin(), (a).end()
#define lowbit(x) ((x) & (-(x)))
#define constructInt4(name, a, b, c, d) name(int a = 0, int b = 0, int c = 0, int d = 0): a(a), b(b), c(c), d(d) {}
#define constructInt3(name, a, b, c) name(int a = 0, int b = 0, int c = 0): a(a), b(b), c(c) {}
#define constructInt2(name, a, b) name(int a = 0, int b = 0): a(a), b(b) {}
#define pchr(a) putchar(a)
#define pstr(a) printf("%s", a)
#define sstr(a) scanf("%s", a)
#define sint(a) scanf("%d", &a)
#define sint2(a, b) scanf("%d%d", &a, &b)
#define sint3(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define pint(a) printf("%d\n", a)
#define test_print1(a) cout << "var1 = " << a << endl
#define test_print2(a, b) cout << "var1 = " << a << ", var2 = " << b << endl
#define test_print3(a, b, c) cout << "var1 = " << a << ", var2 = " << b << ", var3 = " << c << endl typedef long long LL;
typedef pair<int, int> pii;
typedef vector<int> vi; const int dx[] = {, , -, , , , -, -};
const int dy[] = {-, , , , , -, , - };
const int maxn = 1e5 + ;
const int md = ;
const int inf = 1e9 + ;
const LL inf_L = 1e18 + ;
const double pi = acos(-1.0);
const double eps = 1e-; template<class T>T gcd(T a, T b){return b==?a:gcd(b,a%b);}
template<class T>bool max_update(T &a,const T &b){if(b>a){a = b; return true;}return false;}
template<class T>bool min_update(T &a,const T &b){if(b<a){a = b; return true;}return false;}
template<class T>T condition(bool f, T a, T b){return f?a:b;}
template<class T>void copy_arr(T a[], T b[], int n){rep_up0(i,n)a[i]=b[i];}
int make_id(int x, int y, int n) { return x * n + y; } ///行编号从1开始,列编号1~n,结点0是表头结点,结点1~n是各列顶部的虚拟结点
int result;
int b[][]; int encode(int a, int b, int c) {
return a * + b * + c + ;
}
void decode(int code, int &a, int &b, int &c) {
code --;
c = code % ; code /= ;
b = code % ; code /= ;
a = code;
} struct DLX
{
const static int maxn = ;
const static int maxnode = ;
int n , sz; // 行数,节点总数
int S[maxn]; // 各列节点总数
int row[maxnode],col[maxnode]; // 各节点行列编号
int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; // 十字链表 int ansd,ans[maxn]; // 解 void init(int n )
{
this->n = n ;
for(int i = ; i <= n; i++ )
{
U[i] = i ;
D[i] = i ;
L[i] = i - ;
R[i] = i + ;
}
R[n] = ;
L[] = n;
sz = n + ;
memset(S,,sizeof(S));
}
void addRow(int r,vector<int> c1)
{
int first = sz;
for(int i = ; i < c1.size(); i++ ){
int c = c1[i];
L[sz] = sz - ; R[sz] = sz + ; D[sz] = c ; U[sz] = U[c];
D[U[c]] = sz; U[c] = sz;
row[sz] = r; col[sz] = c;
S[c] ++ ; sz ++ ;
}
R[sz - ] = first ; L[first] = sz - ;
}
// 顺着链表A,遍历除s外的其他元素
#define FOR(i,A,s) for(int i = A[s]; i != s ; i = A[i]) void remove(int c) {
L[R[c]] = L[c];
R[L[c]] = R[c];
FOR(i,D,c)
FOR(j,R,i) {U[D[j]] = U[j];D[U[j]] = D[j];--S[col[j]];}
}
void restore(int c) {
FOR(i,U,c)
FOR(j,L,i) {++S[col[j]];U[D[j]] = j;D[U[j]] = j; }
L[R[c]] = c;
R[L[c]] = c;
}
void update() {
int score = ;
rep_up0(i, ansd) {
int r, c, v;
decode(ans[i], r, c, v);
score += (v + ) * b[r][c];
}
max_update(result, score);
}
bool dfs(int d) {
if(R[] == ) {
ansd = d;
update();
return true;
}
// 找S最小的列c
int c = R[];
FOR(i,R,) if(S[i] < S[c]) c = i; remove(c);
FOR(i,D,c) {
ans[d] = row[i];
FOR(j,R,i) remove(col[j]);
//if(dfs(d + 1)) return true;
dfs(d + );
FOR(j,L,i) restore(col[j]);
}
restore(c); //return false;
}
bool solve(vector<int> & v) {
v.clear();
if(!dfs()) return false;
for(int i = ; i < ansd ;i ++) v.push_back(ans[i]);
return true;
}
}; DLX solver;
int a[][]; int main() {
//freopen("in.txt", "r", stdin);
rep_up0(i, ) {
rep_up0(j, ) {
b[i][j] = + min(min(i, - i), min(j, - j));
}
}
int T, x;
cin >> T;
while (T --) {
solver.init();
rep_up0(i, ) {
rep_up0(j, ) {
int x;
sint(x);
rep_up0(k, ) {
if (x == || x == k + ) {
vector<int> col;
col.push_back(encode(, i, j));
col.push_back(encode(, i, k));
col.push_back(encode(, j, k));
col.push_back(encode(, make_id(i / , j / , ), k));
solver.addRow(encode(i, j, k), col);
}
}
}
}
result = -;
solver.dfs();
cout << result << endl;
}
return ;
}

[csu1605]数独(精确覆盖问题)的更多相关文章

  1. hihoCoder #1321 : 搜索五•数独 (Dancing Links ,精确覆盖)

    hiho一下第102周的题目. 原题地址:http://hihocoder.com/problemset/problem/1321 题意:输入一个9*9数独矩阵,0表示没填的空位,输出这个数独的答案. ...

  2. HDU 3111 Sudoku(精确覆盖)

    数独问题,输入谜题,输出解 既然都把重复覆盖的给写成模板了,就顺便把精确覆盖的模板也写好看点吧...赤裸裸的精确覆盖啊~~~水一水~~~然后继续去搞有点难度的题了... #include <cs ...

  3. DLX 舞蹈链 精确覆盖 与 重复覆盖

    精确覆盖问题:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 还有重复覆盖问题 dancing links 是 一种数据结构,用来优化搜索,不算是一种算法.(双向 ...

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

    利用 Dancing Link 来解数独 详细的能够看    lrj 的训练指南 和 < Dancing Links 在搜索中的应用 >这篇论文 Dancing Link 来求解数独 , ...

  5. (简单) POJ 3074 Sudoku, DLX+精确覆盖。

    Description In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgr ...

  6. poj3074 DLX精确覆盖

    题意:解数独 分析: 完整的数独有四个充要条件: 1.每个格子都有填数字 2.每列都有1~9中的每个数字 3.每行都有1~9中的每个数字 4.每个9宫格都有1~9中的每个数字 可以转化成精确覆盖问题. ...

  7. HDU 3111 Sudoku ( Dancing Links 精确覆盖模型 )

    推荐两篇学DLX的博文: http://bbs.9ria.com/thread-130295-1-1.html(这篇对DLX的工作过程演示的很详细) http://yzmduncan.iteye.co ...

  8. 跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题

    精确覆盖问题的定义:给定一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1 例如:如下的矩阵 就包含了这样一个集合(第1.4.5行) 如何利用给定的矩阵求出相应的行的集合 ...

  9. HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)

    很久以前就看到的一个经典题,一直没做,今天拿来练手.街霸 给n<=25个角色,每个角色有 1 or 2 个版本(可以理解为普通版以及爆发版),每个角色版本可以KO掉若干人. 问最少选多少个角色( ...

随机推荐

  1. testNG groups 分组测试

    testNG的分组通过xml文件<groups>标签和@Test(group="组名")来实现分组 xml中关于分组的详细介绍,通过groups 定义一个组,通过< ...

  2. jmeter json path espressions学习

    jsonpath表达式可以使用点或者括号来取值 管方详细介绍:https://goessner.net/articles/JsonPath/ $ :表示根对象 @:表示当前对象 . 或者[]:表示子运 ...

  3. 23-Java-Spring框架(一)

    一.Spring框架了解 Spring框架是一个开源的框架,为JavaEE应用提供多方面的解决方案,用于简化企业级应用的开发,相当于是一种容器,可以集成其他框架(结构图如下). 上图反映了框架引包的依 ...

  4. 学习 .net core 3----蒋金楠 笔记 构建 Asp.net core Web应用

    前言:准备系统的学习一下.net core 所以购买了 蒋金楠的 ASP.NET CORE 3 书籍,为了加深印象 特此笔记,会持续更新到学习完为止 使用  命令行   dotnet  new  co ...

  5. python django mysql配置

    1    django默认支持sqlite,mysql, oracle,postgresql数据库.  <1> sqlite django默认使用sqlite的数据库,默认自带sqlite ...

  6. 如何在github上递交高质量的pull request

    开源的一大乐趣就是任何人都可以参与其中.试想下一个流行的项目就有你贡献的代码,是一件多么爽的事情!你可以帮助项目健康发展,添加你希望添加的功能,以及修复你发现的BUG. 作为全球最大的开源社区GitH ...

  7. 在服务器上发布第一个.net项目

    作为一名前端开发者,对后端一窍不通可是不行的.公司后端所用的恰好是.net技术,日常开发常见MVC架构,然而还是对MVC不甚了解,前端开发也多有掣肘.本人很想摸索清楚如何构建一个asp.net的项目, ...

  8. WFP之位图效果

    首先看一个图片:   在"第一步"这个按钮周围,有一转红色,这个效果就是用WPF的位图效果实现的. 位图效果(BitmapEffect 对象)是简单的像素处理操作.位图效果将 Bi ...

  9. 超轻量级网络SqueezeNet网络解读

    SqueezeNet网络模型非常小,但分类精度接近AlexNet. 这里复习一下卷积层参数的计算 输入通道ci,核尺寸k,输出通道co,参数个数为: 以AlexNet第一个卷积为例,参数量达到:3*1 ...

  10. 【BIM】BIMFACE中创建雾化效果

    背景 在BIM运维场景初始化的时候,一般都是首先将整个运维对象呈现在用户面前,例如一座大厦.一座桥梁.一个园区等等,以便于用户进行总览,总体把握运维对象,如果这个宏大的场景边界过于清晰,与背景融合也不 ...