LA2995——Image Is Everything

这道题我是看刘汝佳的代码才半抄半写的给搞出来了。还抄错了五次……无限怀疑自己智商

第一次看到了宏定义原来可以这么用。

首先是定义了两个数组,一个用于记录看到的情况,就是view,另一个用于记录每一个单位正方体的情况(如果是“.”的话表示这个格子没有东西,“#”说明这个各自有东西但是还没有着色,如果是字母的话就代表了这个格子已经被看到过了。)

然后就是对正方体表示的方式。

对于view数组来说,正方体是有六个面组成,每个面分成了n*n个小格子,

对于每个面,上跟下的定义如图所示,四周全部都是上面就是上,下面就是下,顶面的前面是下,后面是上,底面的前面是上,后面是下。区分这个是为了对每个面的坐标能够更清楚的理解。


 i 和 j 的方向就如图所示,每个面的 i 坐标都是从上到下递增的。

接下来是pos数组的表示方式,这个就很简单了,搞清楚坐标是怎么建的就可以了,如下图。


对于每个面,有函数getp将view中的坐标转换成pos中的坐标,代码的第一步是先将所有能够看穿的地方的正方形全部都给删掉,然后就要进行很多次的循环,直到将正方体给删到满足要求为止。代码如下:

#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;

#define REP(i,n) for(int i=0;i<n;++i)

const int maxn=10;
int n;

int pos[maxn][maxn][maxn];
int view[6][maxn][maxn];

char read_char(){
	char ch;
	for(;;){
		ch=getchar();
		if((ch>='A'&&ch<='Z')||ch=='.')return ch;
	}
}

void getp(int k,int i,int j,int len,int &x,int &y,int &z){
	if(k==0){x=len;y=j;z=i;}
	else if(k==1){x=n-1-j;y=len;z=i;}
	else if(k==2){x=n-1-len;y=n-1-j;z=i;}
	else if(k==3){x=j;y=n-1-len;z=i;}
	else if(k==4){x=n-1-i;y=j;z=len;}
	else if(k==5){x=i;y=j;z=n-1-len;}
}

int main(){
	while(scanf("%d",&n)!=EOF&&n){
		REP(i,n)REP(k,6)REP(j,n) view[k][i][j]=read_char();
		REP(i,n)REP(j,n)REP(k,n) pos[i][j][k]='#';
		for(int k=0;k<6;++k){
			for(int i=0;i<n;++i){
				for(int j=0;j<n;++j){
					if(view[k][i][j]=='.'){
						int x,y,z;
						for(int d=0;d<n;++d){
							getp(k,i,j,d,x,y,z);
							pos[x][y][z]='.';
						}
					}
				}
			}
		}//将能够看穿的删除
	 	for(;;){
	 		bool done=true;
		 	for(int k=0;k<6;++k)
		 	for(int i=0;i<n;++i)
		 	for(int j=0;j<n;++j){
			 	if(view[k][i][j]!='.'){
				 	for(int p=0;p<n;++p){
				 		int x,y,z;
				 		getp(k,i,j,p,x,y,z);
					 	if(pos[x][y][z]=='.')continue;
					 	if(pos[x][y][z]=='#'){
						 	pos[x][y][z]=view[k][i][j];
						 	break;
						 }
						 if(pos[x][y][z]==view[k][i][j]){
						 	break;
						 }
						 pos[x][y][z]='.';
						 done=false;
					 }
				 }//if
		 	}
		 	if(done)break;
	 	}//for
	 	int ans=0;
	 	for(int i=0;i<n;++i)
	 	for(int j=0;j<n;++j)
	 	for(int k=0;k<n;++k){
		 if(pos[i][j][k]!='.')ans++;
		 }
		 cout<<"Maximum weight: "<<ans<<" gram(s)"<<endl;
	}
	return 0;
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

最锻炼思维的一部分就是主循环,

进行如下分析:

for(;;){
	 bool done=true;
	for(int k=0;k<6;++k)
	for(int i=0;i<n;++i)
 	for(int j=0;j<n;++j){
	 	if(view[k][i][j]!='.'){
		 	for(int p=0;p<n;++p){
		 		int x,y,z;
		 		getp(k,i,j,p,x,y,z);
			 	if(pos[x][y][z]=='.')continue;
			 	if(pos[x][y][z]=='#'){
				 	pos[x][y][z]=view[k][i][j];
				 	break;
				 }
				 if(pos[x][y][z]==view[k][i][j]){
				 	break;
				 }
				 pos[x][y][z]='.';
				 done=false;
			 }
		 }//if
 	}if(done)break;	
}//for




内层的判断语句,当一个地方不能够看穿的时候,就需要对这一条条进行操作, if(pos[x][y][z]=='.')continue;当这一个格子已经被删掉了的时候就继续找比它深一个的格子。if(pos[x][y][z]=='#'){
pos[x][y][z]=view[k][i][j];
break;
}
"#"就是表示这个格子还没有进行过判断,那么这个格子就先暂时染上可以看到的颜色。
if(pos[x][y][z]==view[k][i][j]){
break;
 }
如果这个格子的颜色跟能够看到的颜色是一样的,那么就不需要对更深一层的格子进行判断。
如果这三个条件都不满足的话,就表示这个格子现在被染色的颜色跟可以看到的颜色不一样,那么这个格子就需要被删除,在删除以后将标记(done)给改成faulse,这样就保证了最后一次循环的时候没有可以动的格子,也就是不能够再删了。






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值