首页 > 编程语言 >学习老算法,争做老东西

学习老算法,争做老东西

时间:2024-07-09 21:09:51浏览次数:17  
标签:老东西 争做 删除 int 行中 矩阵 链表 算法 MAXN

目录


考虑这样一个问题:

给定一个 \(N\) 行 \(M\) 列的矩阵,矩阵中每个元素要么是 \(1\),要么是 \(0\)。

你需要在矩阵中挑选出若干行,使得对于矩阵的每一列 \(j\),在你挑选的这些行中,有且仅有一行的第 \(j\) 个元素为 \(1\)。

这类问题统称为精确覆盖问题,我们容易得到如下所示的一个想法:

  1. 枚举选择一行,并将其从矩阵中删除。(不重复决策)

  2. 对上一步删除的行内的每个 \(1\),将其所在列删除。(对应列为 \(1\) 的行已确定,可以剪枝)

  3. 对上一步删除的列内的每个 \(1\),将其所在行删除。(避免决策出现某列有多个 \(1\) 的情形)

  4. 若操作后矩阵不为空,回到步骤 1。

  5. 若操作后矩阵为空,但最后一次决策行中元素不全为 \(1\),回溯并回到步骤 1。

  6. 若操作后矩阵为空,且最后一次决策行中元素全为 \(1\),则找到问题的一组解。

不难发现,每个 \(1\) 都是对问题的一个约束;但 \(0\) 只是对矩阵形式上的补足,缺乏实际意义。

所以在实际的精确覆盖问题中,\(0\) 的数量往往远多于 \(1\) 的数量。(以数独问题为例,一个决策中 \(0\) 的个数是数独边长的立方级,而 \(1\) 总是仅有四个)

如果直接使用二维数组模拟这个过程,每个 \(0\) 都要占据空间,空间复杂度通常很糟糕。

所以我们想到,可以用一个动态开点的数据结构,仅维护 \(1\) 的相关信息。

放心,这里并没有什么扫兴的根号和 \(\log\),我们用链表就够了。(大概是高德纳最平易近人的想法)

对每个 \(1\),它沿一个链表遍历过所有与它同列的 \(1\),沿另一个链表遍历过所有与它同行的 \(1\),也就是双向十字链表。(其实可以看成略去那些 \(0\) 之后的网格图,但首尾相接以便遍历)

剩下的其实就是对上述流程的模拟了。

DLX 模板
#include <bits/stdc++.h>
using namespace std;

const int MAXN=250007;
int n,m,cnt,ans,seq[MAXN],dcs[MAXN],sta[MAXN],siz[MAXN],first[MAXN];
int U[MAXN],D[MAXN],L[MAXN],R[MAXN];

void build()
{
	for (int i=0;i<=m;i++)
	{
		L[i]=i-1,R[i]=i+1;
		U[i]=D[i]=i;
	}
	L[0]=m,R[m]=0,cnt=m;
}

void ins(int d,int s)
{
	cnt++,siz[s]++;
	dcs[cnt]=d,sta[cnt]=s;
	U[cnt]=s,D[cnt]=D[s];
	U[D[s]]=cnt,D[s]=cnt;
	if (!first[d]) first[d]=L[cnt]=R[cnt]=cnt;
	else
	{
		L[cnt]=first[d],R[cnt]=R[first[d]];
		L[R[first[d]]]=cnt,R[first[d]]=cnt;
	}
}

void remove(int s)
{
	L[R[s]]=L[s],R[L[s]]=R[s];
	for (int i=D[s];i!=s;i=D[i])
		for (int j=R[i];j!=i;j=R[j])
			U[D[j]]=U[j],D[U[j]]=D[j],siz[sta[j]]--;
}

void recover(int s)
{
	for (int i=U[s];i!=s;i=U[i])
		for (int j=L[i];j!=i;j=L[j])
			U[D[j]]=D[U[j]]=j,siz[sta[j]]++;
	L[R[s]]=R[L[s]]=s;
}

bool dance(int dep)
{
	if (!R[0])
	{
		ans=dep;
		return 1;
	}
	int s=R[0];
	for (int i=s;i!=0;i=R[i])
		if (siz[i]<siz[s]) s=i;
	remove(s);
	for (int i=D[s];i!=s;i=D[i])
	{
		seq[dep]=dcs[i];
		for (int j=R[i];j!=i;j=R[j])
			remove(sta[j]);
		if (dance(dep+1)) return 1;
		for (int j=L[i];j!=i;j=L[j])
			recover(sta[j]);
	}
	recover(s);
	return 0;
}

int main()
{
	cin>>n>>m;
	build();
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
		{
			int x;
			cin>>x;
			if (x) ins(i,j);
		}
	if (dance(1))
		for (int i=1;i<ans;i++)
			cout<<seq[i]<<' ';
	else puts("No Solution!");
	return 0;
}

标签:老东西,争做,删除,int,行中,矩阵,链表,算法,MAXN
From: https://www.cnblogs.com/CrH2/p/18292742

相关文章

  • 基于秃鹰算法的投影寻踪模型 - 附代码
    基于秃鹰算法的投影寻踪模型-附代码文章目录基于秃鹰算法的投影寻踪模型-附代码1.秃鹰算法2.投影寻踪模型3.秃鹰算法结合投影寻踪4.测试结果5.参考文献6.Matlab代码摘要:投影寻踪(projectionpursuit,PP)是处理和分析高维数据的一类新兴统计方法,其基本思想是将高......
  • 基于JAYA算法的投影寻踪模型 - 附代码
    基于JAYA算法的投影寻踪模型-附代码文章目录基于JAYA算法的投影寻踪模型-附代码1.JAYA算法2.投影寻踪模型3.JAYA算法结合投影寻踪4.测试结果5.参考文献6.Matlab代码摘要:投影寻踪(projectionpursuit,PP)是处理和分析高维数据的一类新兴统计方法,其基本思想是将高......
  • 基于供需算法的投影寻踪模型 - 附代码
    基于供需算法的投影寻踪模型-附代码文章目录基于供需算法的投影寻踪模型-附代码1.供需算法2.投影寻踪模型3.供需算法结合投影寻踪4.测试结果5.参考文献6.Matlab代码摘要:投影寻踪(projectionpursuit,PP)是处理和分析高维数据的一类新兴统计方法,其基本思想是将高......
  • 了解Adam和RMSprop优化算法
    优化算法是机器学习和深度学习模型训练中至关重要的部分。本文将详细介绍Adam(AdaptiveMomentEstimation)和RMSprop(RootMeanSquarePropagation)这两种常用的优化算法,包括它们的原理、公式和具体代码示例。RMSprop算法RMSprop算法由GeoffHinton提出,是一种自适应学习率的方......
  • 代码随想录算法训练营第六十三天 | prim算法、kruskal算法、复习
    53.寻宝—prim算法题目链接:https://kamacoder.com/problempage.php?pid=1053文档讲解:https://programmercarl.com/kamacoder/0053.%E5%AF%BB%E5%AE%9D-prim.html思路本题是最小生成树的模板题,最小生成树可以使用prim算法,也可以使用kruskal算法计算出来。prim算......
  • 比较两种计算1到n的累加和的算法的执行效率,理解算法的时间复杂度分析和代码性能优化
    一、实验目的:通过这个实验,旨在比较两种计算1到n的累加和的算法的执行效率,进一步理解算法的时间复杂度分析和代码性能优化。    二、实验内容:1.编写两个函数Sum1和Sum2,分别用于计算1到n的累加和;2.在主函数中调用这两个函数,并通过循环计算1到n的各个累加和;3.使用cloc......
  • 回溯算法-以学生就业管理系统为例
    1.回溯算法介绍1.来源回溯算法也叫试探法,它是一种系统地搜索问题的解的方法。用回溯算法解决问题的一般步骤:1、针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。2、确定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间。3、以深度优先的方式搜索......
  • Dotnet算法与数据结构:Hashset, List对比
    哈希集A是存储唯一元素的集合。它通过在内部使用哈希表来实现这一点,该哈希表为基本操作(如添加、删除和包含)提供恒定时间平均复杂度(O(1))。此外,不允许重复元素,使其成为唯一性至关重要的场景的理想选择。另一方面,表示按顺序存储元素的动态数组。它允许重复元素并提供对元素的索引......
  • 匈牙利算法——棋盘覆盖
    题目描述棋盘覆盖给定一个N行N列的棋盘,已知某些格子禁止放置。求最多能往棋盘上放多少块的长度为2、宽度为1的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。输入格式第一行包含两个整数N和t,其中t为禁止放置的格子的数量。接下来t行每行包含两个整数x......
  • 【TCN-BiGRU-Attention回归预测】基于被囊群优化算法TSA优化时间卷积双向门控循环单元
        ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,代码获取、论文复现及科研仿真合作可私信。......