首页 > 其他分享 >1067. 精确覆盖问题

1067. 精确覆盖问题

时间:2022-11-19 11:36:16浏览次数:83  
标签:覆盖 int 样例 矩阵 1067 精确 define

题目链接

1067. 精确覆盖问题

给定一个 \(N \times M\) 的数字矩阵 \(A\),矩阵中的元素 \(A_{i,j} \in \lbrace 0,1 \rbrace\)。

请问,你能否在矩阵中找到一个行的集合,使得这些行中,每一列都有且仅有一个数字 \(1\)。

输入格式

第一行包含两个整数 \(N\) 和 \(M\)。

接下来 \(N\) 行,每行包含 \(M\) 个整数(\(0\) 或 \(1\)),表示完整的数字矩阵。

输出格式

如果能找到满足条件的行的集合,则在一行中依次输出这些行的编号(行编号 \(1 \sim N\))。

如果方案不唯一,则以任意顺序输出任意方案即可。

否则,输出 No Solution!

数据范围

\(1 \le N,M \le 500\),
数据保证矩阵中 \(1\) 的数量不超过 \(5000\)。

输入样例1:

3 3
0 1 0
0 0 1
1 0 0

输出样例1:

1 2 3

输入样例2:

4 4
0 0 0 1
1 0 0 0
1 1 0 1
0 1 0 0

输出样例2:

No Solution!

解题思路

DLX,精确覆盖

DLX 是一种基于十字链表的搜索算法,主要用来解决精确覆盖问题和重复覆盖问题

对于十字链表,即针对稀疏矩阵,即矩阵中 \(1\) 的个数不多,对于矩阵中 \(1\) 的位置都建立一个节点,每个节点都有上、下、左、右四个循环指针,建立十字链表时一行一行插入,首先插入一行哨兵,后面插入时统一逆插,即将所有矩阵上下和左右翻转,唯一的区别是哨兵行的左右指针没有翻转,这样便区分开了,但要找的是行,对答案没有影响

优化:找到一个含 \(1\) 最少的列,然后再该列中枚举选择哪一行,如果选择某一行,则其他行应该删除,因为精确覆盖每一列有且只有一个 \(1\),另外对于选择的行,其中出现 \(1\) 的列也应该删除,另外需要注意的一点:删除列时对于真正节点只需要在上下方向删除,因为后面对于某含最少个数的 \(1\) 的列,通过上下指针枚举行,而那些要删除的行我们已经在上下方向删除了不会被枚举到,恢复时反向也好恢复

DLX 处理精确覆盖问题甚至有时能处理 \(O(10000)\) 的数据
设 \(n\) 为矩阵中 \(1\) 的个数,\(c\) 为接近 \(1\) 的常数,则:

  • 时间复杂度:\(O(c^n)\)

代码

// Problem: 精确覆盖问题
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/1069/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=5505;
int n,m;
int L[N],R[N],U[N],D[N],s[N],col[N],row[N],idx;
int res[N],top;
void init()
{
	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;
	idx=m+1;
}
void add(int &hh,int &tt,int x,int y)
{
	row[idx]=x,col[idx]=y,s[y]++;
	L[tt]=R[hh]=idx,L[idx]=hh,R[idx]=tt;
	U[idx]=y,D[idx]=D[y],U[D[y]]=idx,D[y]=idx;
	tt=idx++;
}
void remove(int p)
{
	R[L[p]]=R[p],L[R[p]]=L[p];
	for(int i=D[p];i!=p;i=D[i])
		for(int j=R[i];j!=i;j=R[j])
		{
			s[col[j]]--;
			U[D[j]]=U[j],D[U[j]]=D[j];
		}
}
void resume(int p)
{
	for(int i=U[p];i!=p;i=U[i])
		for(int j=L[i];j!=i;j=L[j])
		{
			U[D[j]]=j,D[U[j]]=j;
			s[col[j]]++;
		}
	R[L[p]]=p,L[R[p]]=p;
}
bool dfs()
{
	if(!R[0])return true;
	int p=R[0];
	for(int i=R[0];i;i=R[i])
		if(s[i]<s[p])p=i;
	remove(p);
	for(int i=D[p];i!=p;i=D[i])
	{
		res[++top]=row[i];
		for(int j=L[i];j!=i;j=L[j])remove(col[j]);
		if(dfs())return true;
		for(int j=R[i];j!=i;j=R[j])resume(col[j]);
		top--;
	}
	resume(p);
	return false;
}
int main()
{
    scanf("%d%d",&n,&m);
    init();
    for(int i=1;i<=n;i++)
    {
    	int hh=idx,tt=idx;
    	for(int j=1;j<=m;j++)
    	{
    		int x;
    		scanf("%d",&x);
    		if(x)add(hh,tt,i,j);
    	}
    }
    if(dfs())
    	for(int i=1;i<=top;i++)printf("%d ",res[i]);
    else
    	puts("No Solution!");
    return 0;
}

标签:覆盖,int,样例,矩阵,1067,精确,define
From: https://www.cnblogs.com/zyyun/p/16905722.html

相关文章

  • Android 中OnItemLongClickListener被覆盖
    博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家,......
  • GLASS产品-植被覆盖度FVC数据
    马里兰大学数据中心1.GLASS产品-植被覆盖度FVC_modis(500m)【2000-2018】http://www.glass.umd.edu/FVC/MODIS/500m/2.GLASS产品-植被覆盖度FVC_modis(0.05°)【2000-2018......
  • 如何优雅得修改node_modules里的内容而不被覆盖
    1.安装patch-package插件 npmipatch-package 2.修改node_modules中引入的插件源码之后,运行下方代码npxpatch-package修改的插件名称及package.json中的包......
  • 同一个单元格内实现正负进度条显示,且标签不被进度条覆盖
    一、实现效果二、实现思路假设我们有mysql数据库表temp_namescore,其结构和数据如下:如果我们要实现上述功能,需要将数据转换成可以在前端页面展现的HTML代码,然后在FR中......
  • 棋盘覆盖(java实现)
    棋盘覆盖问题描述在一个2k×2k个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L......
  • 每日一题-区间覆盖
    区间覆盖sort(a.begin(),a.end()); intans=0,las=s; for(inti=0;i<n;++i){ intj=i; intr=-2e9; while(j<nanda[j].first<=......
  • 76.最小覆盖子串
    给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。注意:对于 t 中......
  • HDU 1255 覆盖的面积
    ProblemDescription给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<=T<=100),代表测试......
  • 367页资料详解企业数字化转型,覆盖多行业!附下载
    ​据工信部网站11月8日消息,为助力中小企业数字化转型,工业和信息化部组织相关单位共同研究制定了《中小企业数字化水平评测指标(2022年版)》(以下简称《评测指标》)。《指南》明......
  • 树形DP之点覆盖问题
    什么是点覆盖问题?就是在树上选几个点,覆盖(一个点可以覆盖其相连的边或与其距离不超过\(d\)的点,根据题意具体分析)一些点或边,求最小代价。例题战略游戏题意一棵无根树,......