題目:php
http://poj.org/problem?id=1084html
題意:node
給你一個n*n(n<=5)的徹底由火柴棍組成的正方形,已經去掉了一些火柴棍,問最少去掉多少根火柴棍使得全部1*一、2*2......n*n的正方形均被破壞掉?ios
方法:ide
轉換爲重複覆蓋問題,用DLX直接解決ui
一、精確覆蓋與重複覆蓋:《DLX在搜索中的應用》spa
二、轉換方法:矩陣的一行表明一根火柴棍,矩陣的一列表明一個正方形,即轉換位矩陣重複覆蓋問題code
三、處理去掉的火柴棍:htm
(a)先計算不去掉火柴棍的矩陣,給火柴棍和矩陣編上號手推一下就發現規律了,個人編號和創建矩陣的方法:
1 void calmtx() 2 { 3 row = 2 * n * (n + 1); 4 col = 0; 5 for (int i = 1; i <= n; i++) 6 col += i * i; 7 8 int cnt = 1; 9 for (int si = 1; si <= n; si++) 10 { 11 for (int i = 1; i <= n - si + 1; i++) 12 { 13 for (int j = 1; j <= n - si + 1; j++) 14 { 15 for (int k = 0; k < si; k++) 16 { 17 mtx[(i - 1) * (2 * n + 1) + j + k][cnt] = 1; 18 mtx[(i - 1 + si) * (2 * n + 1) + j + k][cnt] = 1; 19 mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1)][cnt] = 1; 20 mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1) + si][cnt] = 1; 21 } 22 cnt++; 23 } 24 } 25 } 26 }
(b)去掉火柴棍:對去掉的火柴棍對應的正方形加標記並在DLX裏面標記它們已經訪問過,而後在添加link時忽略這些標記過的正方形
1 void build() 2 { 3 calmtx(); 4 5 dlx.initL(col); 6 for (int i = 0; i < vec.size(); i++) 7 { 8 int x = vec[i]; 9 for (int j = 1; j <= col; j++) 10 if (mtx[x][j] && !vis[j]) 11 { 12 vis[j] = 1; 13 dlx.R[dlx.L[j]] = dlx.R[j]; 14 dlx.L[dlx.R[j]] = dlx.L[j]; 15 dlx.R[j] = dlx.L[j] = 0; 16 } 17 } 18 for (int i = 1; i <= row; i++) 19 { 20 for (int j = 1; j <= col; j++) 21 { 22 if (mtx[i][j] && !vis[j]) 23 dlx.Link(i, j); 24 } 25 } 26 }
代碼:
1 /******************************************** 2 *ACM Solutions 3 * 4 *@Title: POJ 1084 Square Destroyer 5 *@Version: 1.0 6 *@Time: 2014-09-29 7 *@Solution: http://www.cnblogs.com/xysmlx/p/xxxxxxx.html 8 * 9 *@Author: xysmlx(Lingxiao Ma) 10 *@Blog: http://www.cnblogs.com/xysmlx 11 *@EMail: xysmlx@163.com 12 * 13 *Copyright (C) 2011-2015 xysmlx(Lingxiao Ma) 14 ********************************************/ 15 // #pragma comment(linker, "/STACK:102400000,102400000") 16 #include <cstdio> 17 #include <iostream> 18 #include <cstring> 19 #include <string> 20 #include <cmath> 21 #include <set> 22 #include <list> 23 #include <map> 24 #include <iterator> 25 #include <cstdlib> 26 #include <vector> 27 #include <queue> 28 #include <stack> 29 #include <algorithm> 30 #include <functional> 31 using namespace std; 32 typedef long long LL; 33 #define pb push_back 34 #define ROUND(x) round(x) 35 #define FLOOR(x) floor(x) 36 #define CEIL(x) ceil(x) 37 const int maxn = 110; 38 const int maxm = 0; 39 const int inf = 0x3f3f3f3f; 40 const LL inf64 = 0x3f3f3f3f3f3f3f3fLL; 41 const double INF = 1e30; 42 const double eps = 1e-6; 43 const int P[4] = {0, 0, -1, 1}; 44 const int Q[4] = {1, -1, 0, 0}; 45 const int PP[8] = { -1, -1, -1, 0, 0, 1, 1, 1}; 46 const int QQ[8] = { -1, 0, 1, -1, 1, -1, 0, 1}; 47 48 /* 49 重複覆蓋:DLX 50 輸入:Link() 51 輸出:ans, bool Dance(int k) 52 */ 53 const int maxnode = 360000; 54 const int maxc = 500; 55 const int maxr = 500; 56 // const int inf = 0x3f3f3f3f; 57 struct DLX 58 { 59 int L[maxnode], R[maxnode], D[maxnode], U[maxnode], C[maxnode]; 60 int S[maxc], H[maxr], size; 61 int ans; 62 ///不須要S域 63 void Link(int r, int c) 64 { 65 S[c]++; C[size] = c; 66 U[size] = U[c]; D[U[c]] = size; 67 D[size] = c; U[c] = size; 68 if (H[r] == -1) H[r] = L[size] = R[size] = size; 69 else 70 { 71 L[size] = L[H[r]]; R[L[H[r]]] = size; 72 R[size] = H[r]; L[H[r]] = size; 73 } 74 size++; 75 } 76 void remove(int c) 77 { 78 for (int i = D[c]; i != c; i = D[i]) 79 L[R[i]] = L[i], R[L[i]] = R[i]; 80 } 81 void resume(int c) 82 { 83 for (int i = U[c]; i != c; i = U[i]) 84 L[R[i]] = R[L[i]] = i; 85 } 86 int h() ///用精確覆蓋去估算剪枝 87 { 88 int ret = 0; 89 bool vis[maxc]; 90 memset (vis, false, sizeof(vis)); 91 for (int i = R[0]; i; i = R[i]) 92 { 93 if (vis[i])continue; 94 ret++; 95 vis[i] = true; 96 for (int j = D[i]; j != i; j = D[j]) 97 for (int k = R[j]; k != j; k = R[k]) 98 vis[C[k]] = true; 99 } 100 return ret; 101 } 102 //根據具體問題選擇限制搜索深度或直接求解。 103 bool Dance(int k) 104 { 105 if (k + h() >= ans) return 0; 106 if (!R[0]) 107 { 108 if (k < ans)ans = k; 109 return 1; 110 } 111 int c = R[0]; 112 for (int i = R[0]; i; i = R[i]) 113 if (S[i] < S[c])c = i; 114 for (int i = D[c]; i != c; i = D[i]) 115 { 116 remove(i); 117 for (int j = R[i]; j != i; j = R[j]) 118 remove(j); 119 Dance(k + 1); 120 for (int j = L[i]; j != i; j = L[j]) 121 resume(j); 122 resume(i); 123 } 124 return 0; 125 } 126 void initL(int x) ///col is 1~x,row start from 1 127 { 128 for (int i = 0; i <= x; ++i) 129 { 130 S[i] = 0; 131 D[i] = U[i] = i; 132 L[i + 1] = i; R[i] = i + 1; 133 }///對列表頭初始化 134 R[x] = 0; 135 size = x + 1; ///真正的元素從m+1開始 136 memset (H, -1, sizeof(H)); 137 ///mark每一個位置的名字 138 } 139 } dlx; 140 141 int kase; 142 int n; 143 vector<int> vec; 144 bool mtx[maxn][maxn]; 145 int row, col; 146 bool vis[maxn]; 147 void init() 148 { 149 kase++; 150 vec.clear(); 151 memset(mtx, 0, sizeof(mtx)); 152 memset(vis, 0, sizeof(vis)); 153 } 154 void input() 155 { 156 scanf("%d", &n); 157 int k; 158 scanf("%d", &k); 159 while (k--) 160 { 161 int x; 162 scanf("%d", &x); 163 vec.pb(x); 164 } 165 } 166 void debug() 167 { 168 // 169 } 170 void calmtx() 171 { 172 row = 2 * n * (n + 1); 173 col = 0; 174 for (int i = 1; i <= n; i++) 175 col += i * i; 176 177 int cnt = 1; 178 for (int si = 1; si <= n; si++) 179 { 180 for (int i = 1; i <= n - si + 1; i++) 181 { 182 for (int j = 1; j <= n - si + 1; j++) 183 { 184 for (int k = 0; k < si; k++) 185 { 186 mtx[(i - 1) * (2 * n + 1) + j + k][cnt] = 1; 187 mtx[(i - 1 + si) * (2 * n + 1) + j + k][cnt] = 1; 188 mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1)][cnt] = 1; 189 mtx[i * n + (i - 1) * (n + 1) + j + k * (2 * n + 1) + si][cnt] = 1; 190 } 191 cnt++; 192 } 193 } 194 } 195 } 196 void build() 197 { 198 calmtx(); 199 200 dlx.initL(col); 201 for (int i = 0; i < vec.size(); i++) 202 { 203 int x = vec[i]; 204 for (int j = 1; j <= col; j++) 205 if (mtx[x][j] && !vis[j]) 206 { 207 vis[j] = 1; 208 dlx.R[dlx.L[j]] = dlx.R[j]; 209 dlx.L[dlx.R[j]] = dlx.L[j]; 210 dlx.R[j] = dlx.L[j] = 0; 211 } 212 } 213 // for (int i = 1; i <= col; i++) 214 // cout << vis[i] << " "; 215 // cout << endl; 216 for (int i = 1; i <= row; i++) 217 { 218 for (int j = 1; j <= col; j++) 219 { 220 if (mtx[i][j] && !vis[j]) 221 dlx.Link(i, j); 222 } 223 } 224 } 225 void solve() 226 { 227 build(); 228 // for (int i = 1; i <= row; i++) 229 // { 230 // for (int j = 1; j <= col; j++) 231 // { 232 // cout << mtx[i][j] << " "; 233 // } 234 // cout << endl; 235 // } 236 // cout << row << " " << col << endl; 237 dlx.ans = inf; 238 dlx.Dance(0); 239 printf("%d\n", dlx.ans); 240 } 241 void output() 242 { 243 // 244 } 245 int main() 246 { 247 // int size = 256 << 20; // 256MB 248 // char *p = (char *)malloc(size) + size; 249 // __asm__("movl %0, %%esp\n" :: "r"(p)); 250 251 // std::ios_base::sync_with_stdio(false); 252 #ifdef xysmlx 253 freopen("in.cpp", "r", stdin); 254 #endif 255 256 kase = 0; 257 int T; 258 scanf("%d", &T); 259 while (T--) 260 { 261 init(); 262 input(); 263 solve(); 264 output(); 265 } 266 return 0; 267 }