【洛谷p1058】立体图(已完结)
立體圖【題目鏈接】
然后因為有點(不是有點,非常)懵,因此我只能看一步寫一步。
首先總體思路:
將三維立體圖看做二維平面圖,先確定出二維圖的長和寬,然后,按照三維立體圖的透視順序,從最后一排的最左開始依次覆蓋操作,直到覆蓋完成,不用的地方填‘.’;
首先是處理二維圖的長和寬:
(首先要說的是,以下所有長均指豎向,寬均為橫向)
經過畫圖找規律我們了解到了對于一個方塊,如果我們在它上面增加一個方塊,對于這個方塊和新增的方塊的某個對應點來說,長增加了3,寬增加0;:
對應點用不同顏色標出;
然后對于前后擺放的情況:
從圖中可以看出,長增加了2,寬增加了2;
然后對于左右擺放的情況:
由圖中可以看出,長莫得增加,寬增加了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; } View Codeend-
轉載于:https://www.cnblogs.com/zhuier-xquan/p/11135044.html
總結
以上是生活随笔為你收集整理的【洛谷p1058】立体图(已完结)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: set dict tuple 内置方法
- 下一篇: vim查找和替换