zoukankan      html  css  js  c++  java
  • 蒟蒻の小窝公开赛 Round 2 T5 3D Cube 题解 [搜索剪枝]

    3D Cube

    Description:

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

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

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

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

    ​ 再举一些例子:

    方块排列 “峰”的数量
    ( exttt{123}) 1
    ( exttt{212}) 2
    ( exttt{122221}) 1
    ( exttt{00011000}) 1
    ( exttt{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 imes mleq25)。在俯视图中每个格子上最多有 (7 imes10^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;
    }
    
  • 相关阅读:
    取消chrome(谷歌浏览器)浏览器下最小字体限制
    函数声明方式及作为值的函数
    常用的正则表达式
    8腾讯云服务器账号密码
    errno -4058 and npm WARN enoent ENOENT 解决方案
    node gyp的问题
    npm 版本问题
    无缘无故出现npm 解析异常的的问题 解决方案
    idea注册码
    以太坊测试网络 账号密码
  • 原文地址:https://www.cnblogs.com/jiangxuancheng/p/14231574.html
Copyright © 2011-2022 走看看