您的位置:首页 > 其它

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)先计算不去掉火柴棍的矩阵,给火柴棍和矩阵编上号手推一下就发现规律了,我的编号和建立矩阵的方法:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: