题目链接:http://acm.hust.edu.cn/problem/show/1017
裸的舞蹈链模版题
关于舞蹈链算法请参考:http://www.cnblogs.com/grenet/p/3145800.html
这个博客讲解的很清楚详细
舞蹈链算法实际上是一个双向十字交叉链表数据结构,解决精确覆盖问题,数独等等都很方便。花了近一天终于搞懂额,纪念一下a的第一道dancing links 啦啦啦~
#include <iostream>
#include <cstdio>
#include<algorithm>
#include <cstring>
#define M_node 1000000
#define M_col 1005
using namespace std;
int n,m; // n 行 m 列
int up[M_node],down[M_node],lleft[M_node],rright[M_node],col[M_node],row[M_node],colnum[M_col],ans[M_col],h[M_col]; // colnum 每列元素数量,ans 结果, h 行头节点
void init()
{
memset(colnum, 0, sizeof(colnum));
memset(ans, 0, sizeof(ans));
memset(h, -1, sizeof(h));
for (int i = 0; i <= m; i ++) // 初始化head及列标节点
{
up[i] = i;
down[i] = i;
if(i == 0) lleft[i] = m;
else lleft[i] = i - 1;
if(i == m) rright[i] = 0;
else rright[i] = i + 1;
col[i] = i;
row[i] = 0;
}
}
void addNode(int r,int c,int id) // 在双向交叉链表中添加元素,id 节点编号
{
row[id] = r; col[id] = c; // 记录行,列
up[id] = up[c]; down[up[c]] = id; // 连接上下
down[id] = c; up[c] = id;
if (h[r] == -1)
{
h[r] = id;
rright[id] = id; lleft[id] = id;
}
else
{
lleft[id] = lleft[h[r]]; rright[lleft[h[r]]] = id;
rright[id] = h[r]; lleft[h[r]] = id;
}
colnum[c] ++;
}
void remove_c(int c) // 删除一列
{
rright[lleft[c]] = rright[c];
lleft[rright[c]] = lleft[c];
for (int i = down[c]; i != c; i = down[i])
{
for (int j = rright[i]; j != i; j = rright[j])
{
down[up[j]] = down[j];
up[down[j]] = up[j];
colnum[col[j]] --;
}
}
}
void resume_c(int c) // 恢复一列
{
rright[lleft[c]] = c;
lleft[rright[c]] = c;
for (int i = up[c]; i != c; i = up[i])
{
for (int j = lleft[i]; j != i; j = lleft[j])
{
down[up[j]] = j;
up[down[j]] = j;
colnum[col[j]] ++;
}
}
}
bool dance(int k) // k 表示进行到第几层
{
if (!lleft[0]) // 列表元素全部为空
{
sort(ans, ans + k);
cout << k << " ";
for (int i = 0;i < k - 1; i ++) cout << ans[i] << " ";
cout << ans[k - 1] << endl;
return true;
}
int s_col = rright[0]; // 记录选中列
for (int i = rright[0]; i != 0; i = rright[i]) // 选择元素最少的一列,减少递归次序
{
if (colnum[s_col] > colnum[i])
{
s_col = i;
}
}
remove_c(s_col);
for (int i = down[s_col]; i != s_col; i = down[i]) // 任意选择该列一行
{
ans[k] = row[i]; // 记录选中行
for (int j = rright[i]; j != i; j = rright[j]) // 删除该行相关列
{
remove_c(col[j]);
}
if (dance(k + 1)) return true; // 继续操作
for (int j = lleft[i]; j != i; j = lleft[j]) // 恢复该行相关列
{
resume_c(col[j]);
}
}
resume_c(s_col);
return false;
}
int main()
{
while (cin >> n >> m)
{
init(); // 建表初始化
int c,t_col,nodeNum = m + 1;
for (int i = 1; i <= n; i ++) // i 行
{
cin >> c;
for(int j = 0; j < c; j ++)
{
cin >> t_col; // 列
addNode(i, t_col, nodeNum);
nodeNum ++;
}
}
if (!dance(0)) cout << "NO" << endl;
}
return 0;
}