蒟蒻の小窝公开赛 Round 2 T5 3D Cube 题解 [搜索剪枝]

3D Cube

Description:

​ 小 Z 拿到了一个二维矩阵。底面可以看作一个 \(n \times m\) 的方格纸。

​ 在每一个格子上,可以放任意个方块。由于有地心引力,方块不会悬空,且不会用胶水粘住。

​ 他给出了这个三维矩阵的三视图,请你构造一个方块组,满足以下条件:

​ 对于每一行、每一列,最多只有一个“”出现。特别地,底层矩阵的周围的高度被视为 \(0\)。如 12321 是一个“峰”,而 13231 有两个“峰”。

​ 再举一些例子:

方块排列 “峰”的数量
\(\texttt{123}\) 1
\(\texttt{212}\) 2
\(\texttt{122221}\) 1
\(\texttt{00011000}\) 1
\(\texttt{10010101}\) 4

求出需要最少方块的矩阵。如果无解,请输出 -1

Input:

​ 第一行两个整数:\(n,m\)

​ 第二行 \(n\) 个整数:左视图,第 \(i\) 个整数表示左视图中第 \(i\) 列的方块个数。

​ 第三行 \(m\) 个整数:主视图,第 \(j\) 个整数表示主视图中第 \(j\) 列的方块个数。

​ 接下来 \(n\) 行,每行 \(m\) 个整数:俯视图,其中 0 表示没有方块,1 表示有方块。

Output:

​ 如果无解,则输出 -1

​ 否则输出共 \(n\) 行,每行 \(m\) 个非负整数,为构造的三维矩阵的俯视图,其中第 \(i\) 行第 \(j\) 个整数表示该位置上的方块个数。

请确保按照输出格式输出,否则可能导致 SPJ 返回 UKE 等结果。

Sample Input:

3 3
2 2 2
2 2 2
0 1 0
1 1 1
0 1 0

Sample Output:

0 2 0 
2 2 2 
0 2 0 

Hint:

本题各部分测试点采用捆绑测试。

​ 对于 \(20\%\) 的数据:给出输入文件,程序打表输出答案,见附件 easy.zip

​ 对于 \(100\%\) 的数据:\(n\times m\leq25\)。在俯视图中每个格子上最多有 \(7\times10^8\) 个方块,且在俯视图中 1 的个数 \(\leq20\)

​ 时间限制: \(2s\)

​ 空间限制: \(256M\)

附件下载

easy.zip \(844B\)

题目分析:

​ 我们发现俯视图中\(1\)的个数是非常少的(毕竟是手造的数据)。于是我们就很容易想到搜索。

​ 我们经过思考可以发现,一个非零位置可以放的数字只有5种选择——

​ 1.为了保证答案最小,可以放个 \(1\)

​ 2.为了使得左视图中某一列的方块数为给定值,我们可以在这个位置上放这一给定值的方块;

​ 3.为了使得主视图中某一列的方块数为给定值,我们可以在这个位置上放这一给定值的方块;

​ 4.为了保证某一列只有一个“”出现,而我们又希望总方块数尽可能的小,我们可以在这个位置放上和同一列上一行方块数一样的方块。

​ 5.为了保证某一行只有一个“”出现,而我们又希望总方块数尽可能的小,我们可以在这个位置放上和同一行上一列方块数一样的方块。

​ 于是复杂度就变成 \(5^{20}\)

​ 当然虽然实际跑不满,但还是不足以过了此题。因此我们考虑各种玄学剪枝——

​ 1.当前放的方块总数已经超过一种合法方案的总数,直接结束。

​ 2.对于每一行边做边判断是否每行都满足左视图的要求,并且这一行只有一个”“,详情见代码;

​ 3.对于每一列边做边判断这一列是否只有一个”“,详情见代码;

​ 通过这些优化剪枝,我们成功水过了此题!

坑点:主视图和左视图中可能某一列为 \(0\) ,需要特殊判断!

​ 代码如下(马蜂很丑,不喜勿喷)——

#include<bits/stdc++.h>
#define LL long long
#define inf 2147483647777
using namespace std;
LL anss=inf,sum;
int n,m,tot,sumx,sumy,ans[30][30],ok1[30],ok2[30],a[30],b[30],xx[30],v[30][30];bool vis[30],ok[30][30];
inline void dfs(int x,int y){
	if(sum>=anss) return;if(y>m){y=1,x++;if(!a[x]&&x<=n) sumx++;if(sumx<x-1) return;}
	if(x==1&&!b[y]) sumy++;if(x==n+1){
		if(sumy<m) return;bool flgg=1;for(register int j=1;j<=m&&flgg;j++){
			bool flg=0;for(register int i=1;i<=n&&flgg;i++){
				int now=i;while(v[now][j]==v[now+1][j]&&now<n) now++;
				if(v[i][j]>v[i-1][j]&&v[i][j]>v[now+1][j]) if(flg) flgg=0;else flg=1;i=now;
			}
		}
		if(!flgg) return;anss=sum;for(register int i=1;i<=n;i++)
		for(register int j=1;j<=m;j++) ans[i][j]=v[i][j];return;
	}
	if(!ok[x][y]){if(v[x][y]<v[x][y-1]){vis[x]=1,dfs(x,y+1),vis[x]=0;}else dfs(x,y+1);return;}if(a[x]<=b[y]){
		if(!ok1[x]) ok1[x]=x*(n+1)+y,sumx++;if(a[x]==b[y]) if(!ok2[y]) ok2[y]=x*(n+1)+y,sumy++;
		sum+=a[x],v[x][y]=a[x];if(v[x][y]<=v[x][y-1]||!vis[x]) if(v[x][y]<v[x][y-1]){vis[x]=1,dfs(x,y+1),vis[x]=0;}else dfs(x,y+1);
		sum-=a[x];if(ok1[x]==x*(n+1)+y) ok1[x]=0,sumx--;if(ok2[y]==x*(n+1)+y) ok2[y]=0,sumy--;
	}
	else{
		if(!ok2[y]) ok2[y]=x*(n+1)+y,sumy++;sum+=b[y],v[x][y]=b[y];
		if(v[x][y]<=v[x][y-1]||!vis[x]) if(v[x][y]<v[x][y-1]){vis[x]=1,dfs(x,y+1),vis[x]=0;}else dfs(x,y+1);
		sum-=b[y];if(ok1[x]==x*(n+1)+y) ok1[x]=0,sumx--;if(ok2[y]==x*(n+1)+y) ok2[y]=0,sumy--;
	}
	for(register int i=1;i<=1;i++) if(xx[i]<a[x]&&xx[i]<b[y]){
		if(xx[i]==a[x]) if(!ok1[x]) ok1[x]=x*(n+1)+y,sumx++;if(xx[i]==b[y]) if(!ok2[y]) ok2[y]=x*(n+1)+y,sumy++;
		sum+=xx[i],v[x][y]=xx[i];if(v[x][y]<=v[x][y-1]||!vis[x]) if(v[x][y]<v[x][y-1]){vis[x]=1,dfs(x,y+1),vis[x]=0;}else dfs(x,y+1);
		sum-=xx[i];if(ok1[x]==x*(n+1)+y) ok1[x]=0,sumx--;if(ok2[y]==x*(n+1)+y) ok2[y]=0,sumy--;
	}
	if(ok[x-1][y]&&v[x-1][y]<a[x]&&v[x-1][y]<b[y]&&v[x-1][y]!=1){
		if(v[x-1][y]==a[x]) if(!ok1[x]) ok1[x]=x*(n+1)+y,sumx++;if(v[x-1][y]==b[y]) if(!ok2[y]) ok2[y]=x*(n+1)+y,sumy++;
		sum+=v[x-1][y],v[x][y]=v[x-1][y];if(v[x][y]<=v[x][y-1]||!vis[x]) if(v[x][y]<v[x][y-1]){vis[x]=1,dfs(x,y+1),vis[x]=0;}else dfs(x,y+1);
		sum-=v[x-1][y];if(ok1[x]==x*(n+1)+y) ok1[x]=0,sumx--;if(ok2[y]==x*(n+1)+y) ok2[y]=0,sumy--;
	}
	if(ok[x][y-1]&&v[x][y-1]<a[x]&&v[x][y-1]<b[y]&&v[x][y-1]!=1){
		if(v[x][y-1]==a[x]) if(!ok1[x]) ok1[x]=x*(n+1)+y,sumx++;if(v[x][y-1]==b[y]) if(!ok2[y]) ok2[y]=x*(n+1)+y,sumy++;
		sum+=v[x][y-1],v[x][y]=v[x][y-1];if(v[x][y]<=v[x][y-1]||!vis[x]) if(v[x][y]<v[x][y-1]){vis[x]=1,dfs(x,y+1),vis[x]=0;}else dfs(x,y+1);
		sum-=v[x][y-1];if(ok1[x]==x*(n+1)+y) ok1[x]=0,sumx--;if(ok2[y]==x*(n+1)+y) ok2[y]=0,sumy--;
	}
}
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) ret=(ret<<1)+(ret<<3)+ch-'0',ch=getchar();
	return ret*f;
}
int main(){
	n=read(),m=read();xx[++tot]=1;
	for(register int i=1;i<=n;i++) a[i]=read(),xx[++tot]=a[i];
	for(register int j=1;j<=m;j++) b[j]=read(),xx[++tot]=b[j];
	sort(xx+1,xx+tot+1);int xxx=tot;tot=1;for(register int i=2;i<=xxx;i++) if(xx[i]!=xx[i-1]) xx[++tot]=xx[i];
	if(!xx[1]){for(register int i=1;i<tot;i++) xx[i]=xx[i+1];tot--;}
	for(register int i=1;i<=n;i++) for(register int j=1;j<=m;j++) ok[i][j]=read();
	dfs(0,m+1);if(anss==inf) cout<<-1;else for(register int i=1;i<=n;puts(""),i++)
	for(register int j=1;j<=m;j++) cout<<ans[i][j]<<' ';return 0;
}
posted @ 2021-01-04 18:49  OdtreePrince  阅读(113)  评论(0编辑  收藏  举报