DLX (精确区间覆盖,重复区间覆盖)(模板)
2014-04-16 14:21
239 查看
参考:白书
http://www.cnblogs.com/jh818012/p/3252154.html
/article/2371298.html
需要注意的是
(1)行列id的hash
(2)行编号从1开始,列编号为1~c,结点0为表头结点
(3)sz和ans等的初始化操作!!!
精确区间覆盖
16*16的数独问题:LA2659
n皇后问题的应用:只枚举部分列即可(这个题的白书模板超时了???)
DLX SPOJ 1771 Yet Another N-Queen
重复区间覆盖:
Problem 1686 神龙的难题
待解决:
http://blog.csdn.net/pi9nc/article/details/11825733(论文中文版)
在n皇后上的应用
每列覆盖特定次数
某些列不需要覆盖
http://www.cnblogs.com/jh818012/p/3252154.html
/article/2371298.html
需要注意的是
(1)行列id的hash
(2)行编号从1开始,列编号为1~c,结点0为表头结点
(3)sz和ans等的初始化操作!!!
精确区间覆盖
16*16的数独问题:LA2659
#include <cstdio> #include <iostream> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int maxnode = 16 * 16 * 16 * 4; const int maxr = 1024; const int maxc = 16 * 16 * 16; ///精确区间覆盖 ///行编号从1开始,列编号为1~c,结点0为表头结点 ///注意给行和列的编号 ///注意sz,ans.要自己初始化和赋值!!! struct DLX { int n , sz; // 每列的行数,节点总数 int S[maxc]; // 各列节点总数 int row[maxnode],col[maxnode]; // 各节点行列编号 int L[maxnode],R[maxnode],U[maxnode],D[maxnode]; // 十字链表 int ansd, ans[maxr]; // 解,行数 void init(int n ) { this->n = n ; for(int i = 0 ; i <= n; i++ ) { U[i] = i ; D[i] = i ; L[i] = i - 1; R[i] = i + 1; } R = 0 ; L[0] = n; sz = n + 1 ; memset(S,0,sizeof(S)); } void addRow(int r,vector<int> c1) { int first = sz; for(int i = 0 ; i < c1.size(); i++ ) { int c = c1[i]; L[sz] = sz - 1 ; R[sz] = sz + 1 ; 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 - 1] = first ; L[first] = sz - 1; } // 顺着链表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; } bool dfs(int d) { if(R[0] == 0 ) { ansd = d; return true; } // 找S最小的列c int c = R[0], tmp = S[R[0]]; FOR(i, R, 0) if (S[i] < tmp) tmp = S[c = i]; // int c = R[0]; // FOR(i,R,0) 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; FOR(j,L,i) restore(col[j]); } restore(c); return false; } bool solve(vector<int> & v) { v.clear(); if(!dfs(0)) return false; for(int i = 0 ; i< ansd ; i ++ ) v.push_back(ans[i]); return true; } }; DLX solver; char s[16][17]; int encode(int x, int y, int z) { return x * 256 + y * 16 + z + 1; } void decode(int val, int &x, int &y, int &z) { --val; z = val % 16; val /= 16; y = val % 16; val /= 16; x = val; } bool read() { for (int i = 0; i < 16; i++) if (scanf("%s", s[i]) != 1) return false; return true; } int main() { int ncase = 1; while (read()) { if (ncase != 1) puts(""); ncase++; solver.init(16 * 16 * 4); for (int i = 0; i < 16; i++) for (int j = 0; j < 16; j++) for (int c = 0; c < 16; c++) { if (s[i][j] == '-' || s[i][j] == 'A' + c) { vector<int>v; v.push_back(encode(0, i, j)); v.push_back(encode(1, i, c)); v.push_back(encode(2, j, c)); v.push_back(encode(3, (i / 4) * 4 + j / 4, c)); solver.addRow(encode(i, j, c), v); } } vector<int>v; solver.solve(v); for (int i = 0; i < v.size(); i++) { int x, y, z; decode(v[i], x, y, z); s[x][y] = 'A' + z; } for (int i = 0; i < 16; i++) puts(s[i]); } return 0; }
n皇后问题的应用:只枚举部分列即可(这个题的白书模板超时了???)
DLX SPOJ 1771 Yet Another N-Queen
Problem (八皇后变形)
重复区间覆盖:Problem 1686 神龙的难题
#include<cstdio> #include <iostream> using namespace std; const int maxnode = 55555; const int maxr = 16 * 16; const int maxc = 16 * 16; int U[maxnode],D[maxnode],L[maxnode],R[maxnode],C[maxnode], row[maxnode]; int H[maxr],S[maxc]; bool v[maxc]; int sz,ans; ///行编号从1开始,列编号为1~c,结点0为表头结点 ///注意给行和列的编号 ///注意sz,ans.要自己初始化和赋值!!! void init(int r,int c)///传入行列数 { for(int i=0; i<=c; ++i) { S[i]=0; D[i]=U[i]=i; L[i+1]=i; R[i]=i+1; } R[sz = c]=0; while(r)H[r--]=-1; } int geth()//?? { int ret=0; for(int c=R[0]; c; c=R[c]) v[c]=1; for(int c=R[0]; c; c=R[c]) if(v[c]) { v[c]=0, ++ret; for(int i=D[c]; i!=c; i=D[i]) for(int j=R[i]; j!=i; j=R[j])v[C[j]]=0; } return ret; } void remove(int c) { for(int i=D[c]; i!=c; i=D[i]) R[L[i]]=R[i],L[R[i]]=L[i]; } void resume(int c) { for(int i=U[c]; i!=c; i=U[i]) R[L[i]]=L[R[i]]=i; } void Dance(int d)///第一次调用传入0 { if(d+geth()>=ans)return; if(!R[0]) { ans=d; return; } // int c = R[0]; // for (i = R[0]; i; i = R[i]) // if (S[i] < R[c]) c = i; int c = R[0], tmp = maxnode; for (int i = R[R[0]]; i; i = R[i]) if (S[i] < tmp) tmp = S[c = i]; for(int i=D[c]; i!=c; i=D[i]) { remove(i); for(int j=R[i]; j!=i; j=R[j])remove(j); Dance(d+1); for(int j=L[i]; j!=i; j=L[j])resume(j); resume(i); } } void Link(int r,int c) { ++S[C[++sz]=c]; D[sz]=D[c]; U[D[c]]=sz; U[sz]=c; D[c]=sz; row[sz] = r; if(H[r]<0)H[r]=L[sz]=R[sz]=sz; else { R[sz]=R[H[r]]; L[R[H[r]]]=sz; L[sz]=H[r]; R[H[r]]=sz; } } int n, m; int a[20][20]; int main() { int nn, mm; while(cin >> n >> m) { sz = 0; for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) { scanf("%d", &a[i][j]); if (a[i][j]) a[i][j] = ++sz; } init(n * m, sz); cin >> nn >> mm; for (int i = 0; i < n - nn + 1; i++) for (int j = 0; j < m - mm + 1; j++) for (int ii = i; ii < i + nn; ii++) for (int jj = j; jj < j + mm; jj++) if (a[ii][jj]) Link(i * m + j + 1, a[ii][jj]); ans = n * m; Dance(0); printf("%d\n", ans); } return 0; }
待解决:
http://blog.csdn.net/pi9nc/article/details/11825733(论文中文版)
在n皇后上的应用
每列覆盖特定次数
某些列不需要覆盖
相关文章推荐
- 最新版dlx模板(精确覆盖+重复覆盖)
- DLX精确覆盖与重复覆盖模板题
- (模板)dlx 精确覆盖和重复覆盖
- DLX模板之精确覆盖和重复覆盖
- dancing link 精确覆盖 重复覆盖 (DLX)
- 精确覆盖DLX算法模板另一种写法
- dancing link 精确覆盖 重复覆盖 (DLX)
- SPOJ 1771&&DLX精确覆盖,重复覆盖
- ZOJ-3209-Treasure Map【6th浙江省赛】【DLX精确覆盖】【模板题】
- HDU 3957 Street Fighter (最小支配集 DLX 重复覆盖+精确覆盖 )
- hdu 3957 Street Fighter 重复覆盖+精确覆盖 DLX
- HDU 3957 Street Fighter(搜索、DLX、重复覆盖+精确覆盖)
- 精确覆盖DLX算法模板
- POJ 3740 DLX 精确覆盖模板题
- DLX 舞蹈链 精确覆盖 与 重复覆盖
- DLX 舞蹈链 精确覆盖+可重复覆盖
- [DLX 精确覆盖 模板题] HUST 1017 Exact cover
- DLX 精确覆盖 重复覆盖
- 【转】DLX 精确覆盖 重复覆盖
- 搜索(DLX重复覆盖模板):HDU 2295 Radar