这道题我是看刘汝佳的代码才半抄半写的给搞出来了。还抄错了五次……无限怀疑自己智商
第一次看到了宏定义原来可以这么用。
首先是定义了两个数组,一个用于记录看到的情况,就是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,这样就保证了最后一次循环的时候没有可以动的格子,也就是不能够再删了。