您的位置:首页 > 编程语言 > C语言/C++

poj 3740 Easy Finding

2014-01-15 00:00 477 查看
摘要: 第一道dancing links,纪念下~

第一道dancing links,纪念下~

Easy Finding

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 15171 Accepted: 4016
Description

Given a
M×
N matrix
A.
A
ij ∈ {0, 1} (0 ≤ i < M, 0 ≤ j < N), could you find some rows that let every cloumn contains and only contains one 1.
Input

There are multiple cases ended by
EOF. Test case up to 500.The first line of input is
M,
N (
M ≤ 16,
N ≤ 300). The next
M lines every line contains
N integers separated by space.
Output

For each test case, if you could find it output "Yes, I found it", otherwise output "It is impossible" per line.
Sample Input
3 3
0 1 0
0 0 1
1 0 0
4 4
0 0 0 1
1 0 0 0
1 1 0 1
0 1 0 0
Sample Output
Yes, I found it
It is impossible
Source

POJ Monthly Contest - 2009.08.23, MasterLuo
[Submit] [Go Back] [Status] [Discuss]

#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#define maxn 5200
#define maxl 305
#define maxm 18
#define head 0

//数组实现的dancing links
int up[maxn] = {0}, down[maxn] = {0}, left[maxn] = {0}, right[maxn] = {0};//顾名思义是某个结点的上下左右结点的标号
int column[maxn] = {0}, row[maxn] = {0}, ans[maxn] = {0};//某个结点对应的行号,ans是取的行号的数组
int m = 0, n = 0;

void init()//初始化
{
memset(up, 0, sizeof(up));
memset(down, 0, sizeof(down));
memset(left, 0, sizeof(left));
memset(right, 0, sizeof(right));
memset(column, 0, sizeof(column));
memset(row, 0, sizeof(row));
memset(ans, 0, sizeof(ans));

return;
}

//这里的remove其实并没有真正删除掉结点,可以用resume恢复
void remove(int c)//去掉c号结点,以及在c所在列上有结点的行的结点
{
left[right[c]] = left[c];
right[left[c]] = right[c];

for (int i = down[c]; i != c; i = down[i])
{
for (int j = right[i]; j != i; j = right[j])
{
up[down[j]] = up[j];
down[up[j]] = down[j];
}
}
return;
}

void resume(int c)//remove的逆操作
{
left[right[c]] = c;
right[left[c]] = c;
for (int i = up[c]; i != c; i = up[i])
{
for (int j = right[i]; j != i; j = right[j])
{
up[down[j]] = j;
down[up[j]] = j;
}
}
return;
}

//我们的终极目标实际上是把十字链表中所有的结点都删掉,只留一个头结点
bool dance(int k)//这里的k实际上是没多大意义的
{
int c = right[head];
if (c == head)//只剩下十字链表的头结点,则完成了目标
{
return true;
}

remove(c);
for (int i = down[c]; i != c; i = down[i])//这里其实是枚举某一行对待匹配行的第c位进行匹配
{
ans[k] = row[i];
for (int j = right[i]; j != i; j = right[j])
remove(column[j]);//remove待匹配行的column[j]结点
if (dance(k + 1))
return true;
for (int j = left[i]; j != i; j = left[j])
resume(column[j]);
}
resume(c);
return false;
}

void test(int idn)//测试用
{
printf("up do le ri co ro\n");
for (int i = 0; i < idn; ++i)
{
printf("%02d %02d %02d %02d %02d %02d\n", up[i], down[i], left[i], right[i], column[i], row[i]);
}
return;
}

int main()
{

while (scanf("%d%d", &m, &n) != EOF)//输入部分极其复杂
{
init();
int id = 1;
int tmp = 0;
int lineup[maxl] = {0};

for (int j = 0; j < n; ++j)//待匹配行
{
lineup[j] = id;
column[id] = j + 1;
if (j != n - 1)
{
right[id] = id + 1;
}
left[id] = id - 1;
++id;
}
right[head] = 1;
left[head] = id - 1;
right[id - 1] = head;

for (int i = 0; i < m; ++i)
{
int first_id = 0;
int left_id = 0;
for (int j = 0; j < n; ++j)
{
scanf("%d", &tmp);
if (tmp)
{
row[id] = i + 1;
column[id] = j + 1;
if (first_id == 0)
{
first_id = id;
left_id = id;
}
else
{
left[id] = left_id;
right[left_id] = id;
left_id = id;
}
int upid = lineup[j];
up[id] = upid;
down[upid] = id;
lineup[j] = id;
++id;
}
}
if (first_id != 0)
{
left[first_id] = left_id;
right[left_id] = first_id;
}
}

for (int j = 0; j < n; ++j)
{
down[lineup[j]] = j + 1;
up[j + 1] = lineup[j];
}

//test(id);

int is_possible = dance(0);

if (is_possible)
printf("Yes, I found it\n");
else
printf("It is impossible\n");

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj cpp dlx dancinglinks