POJ 1084 Square Destroyer (重复覆盖,DLX)
2014-09-29 16:49
225 查看
题目:
http://poj.org/problem?id=1084
题意:
给你一个n*n(n<=5)的完全由火柴棍组成的正方形,已经去掉了一些火柴棍,问最少去掉多少根火柴棍使得所有1*1、2*2......n*n的正方形均被破坏掉?
方法:
转换为重复覆盖问题,用DLX直接解决
1、精确覆盖与重复覆盖:《DLX在搜索中的应用》
http://bbs.whu.edu.cn/wForum/elite.php?file=%2Fgroups%2FGROUP_3%2FACM_ICPC%2Fnx08%2FD.08010000%2FM.1215524645.R0&ap=563
2、转换方法:矩阵的一行代表一根火柴棍,矩阵的一列代表一个正方形,即转换位矩阵重复覆盖问题
3、处理去掉的火柴棍:
(a)先计算不去掉火柴棍的矩阵,给火柴棍和矩阵编上号手推一下就发现规律了,我的编号和建立矩阵的方法:
(b)去掉火柴棍:对去掉的火柴棍对应的正方形加标记并在DLX里面标记它们已经访问过,然后在添加link时忽略这些标记过的正方形
代码:
POJ 1084
http://poj.org/problem?id=1084
题意:
给你一个n*n(n<=5)的完全由火柴棍组成的正方形,已经去掉了一些火柴棍,问最少去掉多少根火柴棍使得所有1*1、2*2......n*n的正方形均被破坏掉?
方法:
转换为重复覆盖问题,用DLX直接解决
1、精确覆盖与重复覆盖:《DLX在搜索中的应用》
http://bbs.whu.edu.cn/wForum/elite.php?file=%2Fgroups%2FGROUP_3%2FACM_ICPC%2Fnx08%2FD.08010000%2FM.1215524645.R0&ap=563
2、转换方法:矩阵的一行代表一根火柴棍,矩阵的一列代表一个正方形,即转换位矩阵重复覆盖问题
3、处理去掉的火柴棍:
(a)先计算不去掉火柴棍的矩阵,给火柴棍和矩阵编上号手推一下就发现规律了,我的编号和建立矩阵的方法:
void calmtx() { row = 2 * n * (n + 1); col = 0; for (int i = 1; i <= n; i++) col += i * i; int cnt = 1; for (int si = 1; si <= n; si++) { for (int i = 1; i <= n - si + 1; i++) { for (int j = 1; j <= n - si + 1; j++) { for (int k = 0; k < si; k++) { mtx[(i - 1) * (2 * n + 1) + j + k][cnt] = 1; mtx[(i - 1 + si) * (2 * n + 1) + j + k][cnt] = 1; mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1)][cnt] = 1; mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1) + si][cnt] = 1; } cnt++; } } } }
(b)去掉火柴棍:对去掉的火柴棍对应的正方形加标记并在DLX里面标记它们已经访问过,然后在添加link时忽略这些标记过的正方形
void build() { calmtx(); dlx.initL(col); for (int i = 0; i < vec.size(); i++) { int x = vec[i]; for (int j = 1; j <= col; j++) if (mtx[x][j] && !vis[j]) { vis[j] = 1; dlx.R[dlx.L[j]] = dlx.R[j]; dlx.L[dlx.R[j]] = dlx.L[j]; dlx.R[j] = dlx.L[j] = 0; } } for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { if (mtx[i][j] && !vis[j]) dlx.Link(i, j); } } }
代码:
/******************************************** *ACM Solutions * *@Title: POJ 1084 Square Destroyer *@Version: 1.0 *@Time: 2014-09-29 *@Solution: http://www.cnblogs.com/xysmlx/p/xxxxxxx.html * *@Author: xysmlx(Lingxiao Ma) *@Blog: http://www.cnblogs.com/xysmlx *@EMail: xysmlx@163.com * *Copyright (C) 2011-2015 xysmlx(Lingxiao Ma) ********************************************/ // #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #include <iostream> #include <cstring> #include <string> #include <cmath> #include <set> #include <list> #include <map> #include <iterator> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <algorithm> #include <functional> using namespace std; typedef long long LL; #define pb push_back #define ROUND(x) round(x) #define FLOOR(x) floor(x) #define CEIL(x) ceil(x) const int maxn = 110; const int maxm = 0; const int inf = 0x3f3f3f3f; const LL inf64 = 0x3f3f3f3f3f3f3f3fLL; const double INF = 1e30; const double eps = 1e-6; const int P[4] = {0, 0, -1, 1}; const int Q[4] = {1, -1, 0, 0}; const int PP[8] = { -1, -1, -1, 0, 0, 1, 1, 1}; const int QQ[8] = { -1, 0, 1, -1, 1, -1, 0, 1}; /* 重复覆盖:DLX 输入:Link() 输出:ans, bool Dance(int k) */ const int maxnode = 360000; const int maxc = 500; const int maxr = 500; // const int inf = 0x3f3f3f3f; struct DLX { int L[maxnode], R[maxnode], D[maxnode], U[maxnode], C[maxnode]; int S[maxc], H[maxr], size; int ans; ///不需要S域 void Link(int r, int c) { S[c]++; C[size] = c; U[size] = U[c]; D[U[c]] = size; D[size] = c; U[c] = size; if (H[r] == -1) H[r] = L[size] = R[size] = size; else { L[size] = L[H[r]]; R[L[H[r]]] = size; R[size] = H[r]; L[H[r]] = size; } size++; } void remove(int c) { for (int i = D[c]; i != c; i = D[i]) L[R[i]] = L[i], R[L[i]] = R[i]; } void resume(int c) { for (int i = U[c]; i != c; i = U[i]) L[R[i]] = R[L[i]] = i; } int h() ///用精确覆盖去估算剪枝 { int ret = 0; bool vis[maxc]; memset (vis, false, sizeof(vis)); for (int i = R[0]; i; i = R[i]) { if (vis[i])continue; ret++; vis[i] = true; for (int j = D[i]; j != i; j = D[j]) for (int k = R[j]; k != j; k = R[k]) vis[C[k]] = true; } return ret; } //根据具体问题选择限制搜索深度或直接求解。 bool Dance(int k) { if (k + h() >= ans) return 0; if (!R[0]) { if (k < ans)ans = k; return 1; } int c = R[0]; for (int i = R[0]; i; i = R[i]) if (S[i] < S[c])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(k + 1); for (int j = L[i]; j != i; j = L[j]) resume(j); resume(i); } return 0; } void initL(int x) ///col is 1~x,row start from 1 { for (int i = 0; i <= x; ++i) { S[i] = 0; D[i] = U[i] = i; L[i + 1] = i; R[i] = i + 1; }///对列表头初始化 R[x] = 0; size = x + 1; ///真正的元素从m+1开始 memset (H, -1, sizeof(H)); ///mark每个位置的名字 } } dlx; int kase; int n; vector<int> vec; bool mtx[maxn][maxn]; int row, col; bool vis[maxn]; void init() { kase++; vec.clear(); memset(mtx, 0, sizeof(mtx)); memset(vis, 0, sizeof(vis)); } void input() { scanf("%d", &n); int k; scanf("%d", &k); while (k--) { int x; scanf("%d", &x); vec.pb(x); } } void debug() { // } void calmtx() { row = 2 * n * (n + 1); col = 0; for (int i = 1; i <= n; i++) col += i * i; int cnt = 1; for (int si = 1; si <= n; si++) { for (int i = 1; i <= n - si + 1; i++) { for (int j = 1; j <= n - si + 1; j++) { for (int k = 0; k < si; k++) { mtx[(i - 1) * (2 * n + 1) + j + k][cnt] = 1; mtx[(i - 1 + si) * (2 * n + 1) + j + k][cnt] = 1; mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1)][cnt] = 1; mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1) + si][cnt] = 1; } cnt++; } } } } void build() { calmtx(); dlx.initL(col); for (int i = 0; i < vec.size(); i++) { int x = vec[i]; for (int j = 1; j <= col; j++) if (mtx[x][j] && !vis[j]) { vis[j] = 1; dlx.R[dlx.L[j]] = dlx.R[j]; dlx.L[dlx.R[j]] = dlx.L[j]; dlx.R[j] = dlx.L[j] = 0; } } // for (int i = 1; i <= col; i++) // cout << vis[i] << " "; // cout << endl; for (int i = 1; i <= row; i++) { for (int j = 1; j <= col; j++) { if (mtx[i][j] && !vis[j]) dlx.Link(i, j); } } } void solve() { build(); // for (int i = 1; i <= row; i++) // { // for (int j = 1; j <= col; j++) // { // cout << mtx[i][j] << " "; // } // cout << endl; // } // cout << row << " " << col << endl; dlx.ans = inf; dlx.Dance(0); printf("%d\n", dlx.ans); } void output() { // } int main() { // int size = 256 << 20; // 256MB // char *p = (char *)malloc(size) + size; // __asm__("movl %0, %%esp\n" :: "r"(p)); // std::ios_base::sync_with_stdio(false); #ifdef xysmlx freopen("in.cpp", "r", stdin); #endif kase = 0; int T; scanf("%d", &T); while (T--) { init(); input(); solve(); output(); } return 0; }
POJ 1084
相关文章推荐
- [DLX重复覆盖] poj 1084 Square Destroyer
- POJ 1084(DLX重复覆盖)
- 【POJ1084】Square Destroyer 重复覆盖问题 DLX(Dancing Links)
- POJ1084-重复覆盖,DLX
- (中等) POJ 1084 Square Destroyer , DLX+可重复覆盖。
- [DLX反复覆盖] poj 1084 Square Destroyer
- POJ 1084 Square Destroyer【Dancing Links重复覆盖】
- zoj 1031& poj 1084 (Dancing Links 重复覆盖)
- POJ_1084_SquareDestroyer(DancingLinksX重复覆盖)
- DLX (重复覆盖+费用不为1的最小费用)fzu Problem 2165 v11
- [DLX重复覆盖] hdu 3529 Bomberman - Just Search!
- [DLX重复覆盖] hdu 3656 Fire station
- DLX(重复覆盖)FZU1686神龙的难题
- FZU 1686 神龙的难题(DLX 重复覆盖)
- [DLX重复覆盖] hdu 3957 Street Fighter
- FZU 1686 神龙的难题(DLX可重复覆盖)
- DLX模板之精确覆盖和重复覆盖
- POJ_3740——精确覆盖问题,DLX模版
- (中等) HDU 5046 Airport ,DLX+可重复覆盖+二分。
- POJ 3074 Sudoku(DLX+精确覆盖)