dancing links (精确覆盖+重复覆盖)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39562952/article/details/83177463

精确覆盖模板:(解决的问题是在01矩阵中选出最少的行,另每一列都有且只有一个1)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
const int MN = 1005;//最多的行数 
const int MM = 1005;//最多的列数 
const int MNN = 1e5 + 5 + MM; //最大节点数
struct DLX
{
	int n, m, si;//行数,列数,目前使用的节点数
	int U[MNN], D[MNN], L[MNN], R[MNN], Row[MNN], Col[MNN];
	//第i个结点的U向上指针D下L左R右,所在位置Row行Col列
	int row[MN], col[MM];//记录行的选择情况和列的覆盖情况
	int ansd, ans[MN];//答案的总数,答案
	void init(int n, int m)//初始化空表 
	{
		for (int i = 0; i <= m; i++)
		{
			col[i] = 0;//说明i列没1覆盖
			U[i] = D[i] = i;//目前的纵向是空的,所以上下都指着自己
			L[i] = i - 1;
			R[i] = i + 1;//横向连接 
		}
		L[0] = m;
		R[m] = 0;//第0行首尾相连
		si = m;//目前用了前0-m个节点
		for (int i = 1; i <= n; i++)
			row[i] = -1;//i行没被选择过 
	}
	void add(int r, int c)//插入节点,节点位置在(r,c)
	{
		si++;
		Col[si] = c;//该节点在c列
		col[c]++;//c列多了一个1
		Row[si] = r;//该节点在r行
		D[si] = D[c], U[D[c]] = si;
		U[si] = c, D[c] = si;//c是列首,si是列尾,所以u列尾=列首
		if (row[r] < 0)
			row[r] = L[si] = R[si] = si;
		else
		{
			R[si] = R[row[r]];//si的右边=行首的右边 
			L[R[row[r]]] = si;//行首的右边的左边变成si 
			L[si] = row[r];//si的左边=行首 
			R[row[r]] = si;//行首的右边的=si 
		}


	}
	void remove(int c)//删除c列
	{
		L[R[c]] = L[c];
		R[L[c]] = R[c];
		for (int i = D[c]; i != c; i = D[i])//从列首下一个开始删除,直到删光这一列 
		{
			for (int j = R[i]; j != i; j = R[j])//删除列中每个元素对应行上的元素(即是从纵向上删除)
			{
				U[D[j]] = U[j];
				D[U[j]] = D[j];
				col[Col[j]]--;//那列的元素个数减一 
			}
		}
	}
	void resume(int c)//恢复c列
	{
		L[R[c]] = c;//把c回复到0行 
		R[L[c]] = c;
		for (int i = U[c]; i != c; i = U[i])
		{
			for (int j = R[i]; j != i; j = R[j])
			{
				U[D[j]] = j;
				D[U[j]] = j;
				col[Col[j]]++;
			}
		}


	}
	int dance(int d)//选取了一共d行 
	{
		if (R[0] == 0)//全覆盖
		{
			ansd = d;
			return 1;
		}
		int c = R[0];
		for (int i = R[0]; i != 0; i = R[i])//删除最少元素的列 
		{
			if (col[i] < col[c])
			{
				c = i;
			}
		}
		remove(c);
		for (int i = D[c]; i != c; i = D[i])
		{
			ans[d] = Row[i];
			for (int j = R[i]; j != i; j = R[j])
			{
				remove(Col[j]);//删除j对应的列 
			}
			if (dance(d + 1))
				return 1;
			for (int j = L[i]; j != i; j = L[j])
			{
				resume(Col[j]);//恢复j对应的列 
			}
		}
		resume(c);//恢复c列 
		return 0;
	}
}dlx;
int main()
{
	





	return 0;
}

重复覆盖模板:(解决的问题是在01矩阵中选出最少的行,另每一列都至少有一个1)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream> 
using namespace std;

const int NUM = 100 * 60;
struct SLX
{
	int U[NUM], D[NUM], L[NUM], R[NUM];//上下左右的邻居
	int Col[NUM], Row[NUM];//每个元素对应的列行
	int col[NUM], row[NUM];//每一列的元素个数,行的行首 
	int si;
	int ans[1000], ansd;
	void ini(int n, int m)
	{
		for (int i = 0; i <= m; i++)
		{
			R[i] = i + 1;
			L[i] = i - 1;
			D[i] = U[i] = i;
			Col[i] = i;
			Row[i] = 0;
			col[i] = 0;
		}
		R[m] = 0;
		L[0] = m;
		si = m;
		for (int i = 1; i <= n; i++)
		{
			row[i] = -1;
		}
	}
	void add(int r, int c)
	{
		si++;
		Col[si] = c;
		Row[si] = r;
		col[c]++;
		D[si] = D[c];
		U[D[c]] = si;
		U[si] = c;
		D[c] = si;
		if (row[r] < 0)
		{
			row[r] = R[si] = L[si] = si;
		}
		else
		{
			R[si] = R[row[r]];
			L[R[row[r]]] = si;
			L[si] = row[r];
			R[row[r]] = si;
		}
	}
	void remove(int c)
	{
		for (int i = D[c]; i != c; i = D[i])
		{
			R[L[i]] = R[i];
			L[R[i]] = L[i];
		}
	}
	void resume(int c)
	{
		for (int i = D[c]; i != c; i = D[i])
		{
			R[L[i]] = L[R[i]] = i;
		}
	}
	int geth()//最少还要处理几列 
	{
		int ret = 0;
		bool vis[80];
		memset(vis, 0, sizeof(vis));
		for (int c = R[0]; c; c = R[c])
		{
			if (!vis[c])
			{
				
				ret++;
				for (int i = D[c]; i != c; i = D[i])
				{
					for (int j = R[i]; j != i; j = R[j])
					{
						vis[Col[j]] = true;
					}
				}
			}

		}
		return ret;
	}
	void dance(int k)
	{
		
		if (!R[0])
		{
			ansd = min(ansd, k);
			return;
		}
		else if(k+geth()>=ansd)
		{
			return;
		}
		int c = R[0];
		for (int i = R[0]; i; i = R[i])
		{
			if (col[i] < col[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);
				col[Col[j]]--;
			}
				
			dance(k + 1);
			for (int j = L[i]; j != i; j = L[j])
				resume(j),col[Col[j]]++;
			resume(i);
		}

	}
}dlx;
int main()
{

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39562952/article/details/83177463
今日推荐