01矩阵问题

求极大全1矩阵个数

派大星有一个n*m的的矩阵。
定义全1子矩阵:为仅包含 0和1的子矩阵。
定义极大全 矩阵:

  • 首先该矩阵是全 矩阵。
  • 其次该矩阵不是其它某个全 矩阵的子矩阵。

派大星想知道它的矩阵中包含多少个极大全1 矩阵。

思路:

类似题目,演算法笔记上引出的问题是求面积最大的全1矩阵,这道题类似做法,在处理最大矩阵的过程中,判断当前的这个矩阵是否会被包含在后续求出来的矩阵中,假设在当前的行处理出最大的矩阵,那么要在知道会不会被包含在下一行的矩阵中,只要知道当前这一行,这个矩阵的对应的1位置,如果下一行中也全为1,那么一定会被包含,如果下一行中对应位置中有一个位置为0,那么说明这个矩阵不会被包含在下一行的最大矩阵中。做法和求面积最大全1矩阵一样,加个这个判断包含关系就行。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
typedef vector<int>vi;

#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define fi first
#define se second
#define de(x) cout<<#x<<"="<<x<<endl;
#define dd(x) cout<<#x<<"="<<x<<" " ;
#define pb(x) push_back(x)
#define per(i,a,b) for(int i=(b)-1;i>=(a);--i)
const int N=5e3+5;
char mp[N][N]; 
int h[N][N];
int area[N][N];
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		scanf("%s",mp[i]+1);
	}
	memset(h,0,sizeof(h));
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)
			if(mp[i][j]=='1'){
				h[i][j]=h[i-1][j]+1;
			}
	int ans=0;
	for(int i=1;i<=n;++i){
		stack<pii>stk;
		int ma=-1;
		for(int j=1;j<=m+1;++j){
			int pos=j;
			while(!stk.empty()&&stk.top().fi>h[i][j]){
				if(stk.top().se<=ma){
					ans++;
				}
				pos=stk.top().se;
				stk.pop();
			}
			if(!h[i+1][j])ma=j;
			if(h[i][j]&&(stk.empty()||(stk.top().fi<h[i][j])))
				stk.push(pii(h[i][j],pos));
		}	
	}
	cout<<ans<<endl;
	return 0;
}

求面积最大

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
typedef vector<int>vi;

#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define fi first
#define se second
#define de(x) cout<<#x<<"="<<x<<endl;
#define dd(x) cout<<#x<<"="<<x<<" " ;
#define pb(x) push_back(x)
#define per(i,a,b) for(int i=(b)-1;i>=(a);--i)
const int N=1e2+5;
char mp[N][N];
int wl[N][N];
int main()
{
	int t;
	cin>>t;
	int n,m,q;
	while(t--){
		cin>>n>>m>>q;
		rep(i,1,n+1)
			scanf("%s",mp[i]+1);
		memset(wl,0,sizeof(wl));
		rep(i,1,n+1)
			rep(j,1,m+1){
				if(mp[i][j]==mp[i][j-1])wl[i][j]=wl[i][j-1]+1;
				else wl[i][j]=1; 
			}
		cout<<n<<" "<<m<<" "<<q<<endl;
		while(q--){
			int r,c;
			cin>>r>>c;
			r++;
			c++;
			int ma=min(m,n);
			int ans=1;
			for(int i=1;i<=ma;++i){
				if(r+i>n||r-i<1||c+i>m||r-i<1)
					break;
	
				bool f=false;
				for(int j=r-i;j<=r+i;++j){
				
					if(mp[j][c+i]!=mp[r][c]||wl[j][c+i]<i*2+1){
						f=true;
						break;
					}
				
				}
				
				if(!f)ans=i*2+1;
				else break;
			} 
			cout<<ans<<endl;
		} 
	}
	return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值