poj 3740 Easy Finding

第一道dancing links,纪念下~


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

Description

Given a  M× N matrix  AA 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  MN ( 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)