立体图【题目连接】ios
而后由于有点(不是有点,很是)懵,所以我只能看一步写一步。数组
首先整体思路:ide
将三维立体图看作二维平面图,先肯定出二维图的长和宽,而后,按照三维立体图的透视顺序,从最后一排的最左开始依次覆盖操做,直到覆盖完成,不用的地方填‘.’;spa
首先是处理二维图的长和宽:3d
(首先要说的是,如下全部长均指竖向,宽均为横向)code
通过画图找规律咱们了解到了对于一个方块,若是咱们在它上面增长一个方块,对于这个方块和新增的方块的某个对应点来讲,长增长了3,宽增长0;:blog
对应点用不一样颜色标出;字符串
而后对于先后摆放的状况:get
从图中能够看出,长增长了2,宽增长了2;string
而后对于左右摆放的状况:
由图中能够看出,长莫得增长,宽增长了4;
而后对应如下数组:
//宽的增长量 int dm[4]={0,0,4,2};//1竖着摞,2横着摞,3先后摞 //长的增长量 int dn[4]={0,3,0,2};//1竖着摞,2横着摞,3先后摞
而后咱们求一下咱们要存的二维平面的大小:
对于横放的宽:从最左下角开始计算,先计算
中,最右下的位置(图中红圈内紫色点的位置);
=(m-1)*dm[2]+5(首先第一个方块占了5个单位,而后剩余的m-1个方块,每放一个,增长4个单位)
计算完成后,再计算
中剩余位置也就是红圈‘+’所在位置,如何计算剩下的长度呢,咱们须要用到先后摆放的增长量:仍是一样,首先先把第一个方块单列,这个方块的(右面吧)为宽提供了3的价值(可是要注意的是,由于第一个方块最左下的贡献与上面的计算重复了,因此实际咱们只须要+2),剩余n-1个方块,每一个为宽提供了2个价值。
所以宽mm=5+(m-1)*dm[2]+(n-1)*dm[3]+2;
再来看长,由于lz看的题解的博主:小蒟蒻皮皮鱼(友情安利,这是个大佬)他本身说他比较菜,用的枚举的方法,lz也只看懂了枚举的方法:
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) nn=max(nn,atlas[i][j]*dn[1]+dn[3]*(n-i+1)+1); //枚举每个点的长,取最大值
一样算最高的,先算出:atlas[i][j]*dn[1]+1(其中atlas为输入的矩阵数据),算出的是粉线部分,而后(n-i+1)这个表示的是第几排(由于数组是:↓→这样存储的,可是实际上咱们要画的是↑→的图,所以要减一下)对于第(n-i+1)排,它的上面对长的贡献就是dn[3]*(n-i+1)(这里再也不加一是由于有一个点前面和上面都有贡献,咱们只须要加一次(绿点处)),也就是每一个方块对长贡献2;(固然要枚举取最高的)
而后考虑一张图,咱们按照透视的顺序,从后往前,从左往右的依次添加覆盖,首先是最左下的立方体(其实通常会被所有覆盖掉,但咱们仍是要加),而后咱们固定一个点,为立方体的定位点,以此点为基础拓展出整个立方体,因此最关键的一点就是定位立方体了:
这里定位立方体的左下角:
而后就是咋的定位了,
而后咱们仍是看个样例:(啊算了,我补不出来(艰难))
(百度网图qwq)
而后你看这个图,输入的数据中为atlas[1][1]的立方体的左下角就是红点标出的地方,而后咱们求出的nn是绿色线标出的地方,mm是紫色线标出的地方,这样咱们在存二维数组时,先存最左下角的立方体:
求某个立方体左下角坐标:
对于x(与nn(长)同方向的那个),咱们显然只须要考虑dn对其的影响;(上下)
而后由于咱们的思路是:
求出红点的在二维平面的坐标,而后给对于每一个立方体上面再摞立方体。
因此不用把层数>=2的左下角求出来;
回到这个图:
咱们应该如何求这个点的x呢??
先放代码(由于发现莫得代码不知道咋的讲):
for(int i=1;i<=n;i++){ for(int j=1,x,y;j<=m;j++){ x=nn-dn[3]*(n-i); y=dm[3]*(n-i)+dm[2]*(j-1)+1; zhetizhenduliu(i,j,x,y); } }
根据咱们楼上的经验,对于每一横行来讲,每向后放置一个立方体,对应点的x就会+dn[3],所以咱们在计算x时,考虑这个立方体相对于第一排立方体向后挪了几个,由于数组atlas[1][i]其实对应的是最后一行,因此咱们覆盖是从1↓m,1→n。(n-i)表示的就是咱们从第一行向后放了几个立方体到达了咱们当前要放立方体的这一行,楼上红点就是3-1,表示咱们在放这个方块以前已经放了两个方块,每放一个方块,x就要相对于绿线 所在地方向后dn[3](2)个,由于绿线是最大的位置,因此实际咱们须要用nn-(n-i)*dn[3];
而后对于y(与mm方向相同)(宽)
啊又要画图
仍是先推第一排的立方体,假设j=2(先无论i了在这不重要)
那么很显然这个点首先要计算的仍是第一排的位置,也就是(j-1)*dm[2]+1(每左右放一个方块增长4,由于咱们求的是左下角,因此不能用j乘而是要用(j-1)乘(而后别忘了+1)。
而后再算先后摆放形成的影响,也是一样,对于先后摆放,每摆放一个,左下角的位置向右挪2,而后也是从后往前记得编号嘛,因此仍是要用(n-i)*dm[3];
而后定位好了左下角,咱们能够尝试开始覆盖了:
inline void zhetizhenduliu(int i,int j,int x,int y){ //x,y表示咱们定位点的左下角坐标,i,j表示咱们定位点应该是输入矩阵的哪个坐标; int a,b; while(atlas[i][j]--){ for(a=0;a<6;a++) for(b=0;b<7;b++) if(s1[6-a-1][b]!='.') s[x-a][y+b]=s1[6-a-1][b]; x-=3; } }
而后忘记讲的一件事,咱们要先将立方体打好表:
char s1[6][8]= { "..+---+", "./ /|", "+---+ |", "| | +", "| |/.", "+---+.." };//真好看的说
而后你看这是个6*7的表,但开了6*8,你开6*7会炸,由于对于字符串, 除了你存的字符外,它会再存入一个我也忘了叫啥的某个东西,所以咱们要多开一个;
而后覆盖:
首先要讲的是,咱们只计算了最底层的立方体的左下角位置,而后是向上摞立方体,当咱们每向上摞一个立方体时,长就 -=3;(由于咱们输出是从上往下输出,因此越靠近输出的最上方的立方体的长其实越小,也就是须要 -=3而不是+=3的缘由)这是最外层while循环;
咱们计算出来的(x,y)实际上对应到s1数组中是s1[6][0];
用s数组存最终覆盖后的答案,那么注意要判断的是s1[i][j](表示s1数组中某一个位置)!='.'或许你会像我同样开始时认为没什么用,可是若是你不加这一句:
你就wa声一片了;
注意的是,这里s数组是从1开始存的,而s1数组是从0开始存的;
而后应该能够理解的吧,由于咱们定位的是左下角,因此对于其余任意一个点,均可以由左下角的点的坐标加加减减得出,并且对于长,必定是减,对于宽,必定是加(加减均包括0),而后就枚举就好啦;
附上ych小蒟蒻皮皮鱼的神仙代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<queue> using namespace std; inline int read() { int ans=0; char last=' ',ch=getchar(); while(ch<'0'||ch>'9') last=ch,ch=getchar(); while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=getchar(); if(last=='-') ans=-ans; return ans; } int n,m; char s1[6][8]= { "..+---+", "./ /|", "+---+ |", "| | +", "| |/.", "+---+.." }; int dm[4]= {0,0,4,2}; int dn[4]= {0,3,0,2}; char s[1000][1000]; int atlas[51][51]; int mm,nn; inline void zhetizhenduliu(int i,int j,int x,int y) { int a,b; while(atlas[i][j]--) { for(a=0; a<6; a++) for(b=0; b<7; b++) if(s1[6-a-1][b]!='.') s[x-a][y+b]=s1[6-a-1][b]; x-=3; } } int main() { n=read(),m=read(); for(int i=1; i<=1000; i++) for(int j=1; j<=1000; j++) s[i][j]='.'; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) atlas[i][j]=read(); mm=7+(n-1)*dm[3]+(m-1)*dm[2]; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) nn=max(nn,atlas[i][j]*dn[1]+dn[3]*(n-i+1)+1); for(int i=1; i<=n; i++) { for(int j=1,x,y; j<=m; j++) { x=nn-dn[3]*(n-i); y=dm[3]*(n-i)+dm[2]*(j-1)+1; zhetizhenduliu(i,j,x,y); } } for(int i=1; i<=nn; i++) { for(int j=1; j<=mm; j++) { printf("%c",s[i][j]); } puts(""); } return 0; }
end-