洛谷 Luogu P1058 <立体图>∪P8217 <数正方体>

这篇博客介绍了如何解决数正方体和重建字符画的问题,通过头顶标数法解决数正方体,从底部向上寻找斜线确定柱状体高度。对于重建问题,从左往右、从下往上、从后往前堆砌块,解决犬牙交错的图形。提供了解题思路和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

立体图传送门

数正方体传送门

相信很多第一眼看到这两道题数据和题目的人都会想到:

学霸题

数正方体

头顶标数法

从上往下数

 梗出处传送门

这两道题乍一看难度,哎呀!一黄一绿,简直是美丽极了,对小蒟蒻来说似乎不是很友好,但实际上仔细想想也不难,我们先从绿色的数正方体开始讲(主要因为我先A的这一道)

P8217

先观察数据:

//输入数据
14 17
....+---+---+....
.../   /   /|....
..+---+---+ |....
./   /|   | +---+
+---+ |   |/   /|
|   | +---+---+ |
|   |/   /|   | +
+---+---+ |   |/|
|   |   | +---+ |
|   |   |/   /| +
+---+---+---+ |/.
|   |   |   | +..
|   |   |   |/...
+---+---+---+....
//输出数据
14

第一眼看到真的挺难,但是仔细一想,我们可以用小兔老师教我们的头顶标数法,具体的实现方法是从上往下找顶面,也就是:

  +---+ 
 /   /
+---+

一旦我们找到一个顶面就代表一竖列的结束,这时ans+=该列高度。

实际上,这个苦逼思路只能过样例,交上去全RE

一个主要原因就是该代码变量实在太多,太复杂,写出来也很难调,至少我是调不动了

这时,我们不妨换一下思路:

我们观察样例,发现每个竖列的顶端一定是斜的,就是一定有  "/   /" 我们想可不可以简化一下,我们字符画的最底下开始找,每遇到一个加号开始向上找,并维护一个tot变量,当我们找到顶端时,ans+=tot,注意tot此时不归零,然后将坐标挪到后面一列,并继续向上寻找,直到边界,最终ans就是答案。

上一发过的代码(详解):

#include<bits/stdc++.h>
using namespace std;
int r,c,n;
char a[1005][1005];
int getn(){
	int cnt=0;//定义计数器
	for(int i=1;i<=c;i++){
		if(a[r][i]=='+')cnt++;//遇到加号则计数
	}
	return cnt-1;//因为最终会多出一个,观察数据可知,所以减一
}
int main(){
	cin>>r>>c;
	for(int i=1;i<=r;i++){
		scanf("\n");
		for(int j=1;j<=c;j++){
			scanf("%c",&a[i][j]);
		}
	}
    //如果临时不会用getline了就这样写,之所以不用getchar是因为一些系统的换行符不同    
    //比如有的是\r\n,有的是\n
	n=getn();//这个函数用来得到n,n就是题目中的n。
	int ans=0,t;//t是为了保持k的不变性,具体后面说。
	for(int k=1;k<=n*4-3;k+=4){
		int tot=0;//可以理解为当前的层数
		t=k;//先将当前k存下,k指的是目前的X坐标
		for(int nowx=r;nowx>=1;){
			if(a[nowx-1][k+1]==' '){
                //如果我们要判断是否是左斜杠的位置是空格,那么直接tot++
                //这是为了特判彻底到顶导致上面是.的情况
				tot++;
				nowx-=3;
			}else if(a[nowx-1][k+1]=='/'){//如果上方是/,代表一列搜到头了。
				ans+=tot;
				nowx-=2;
				k+=2;
			}else{//如果已经到顶
				break;//退出循环
			}
		}
		k=t;//把k赋值回t,因为在查找操作中已经对k进行了操作。
	}
	cout<<ans;//输出答案
	return 0;
} 

P1058

这题一看,不就是P8217の逆吗?但是,在p8217中,题目保证没有列的顶端被挡住,这也是我们可以用头顶标数法的基础。而这题是各种犬牙交错……

所以怎么做?

遇到这类问题不要慌,我们想一下,每一个块仅仅有可能被什么挡住?答案是它前面、右面、上面的块,所以思路出来了,就是从左往右,从下往上,从后往前堆块。

代码:

#include<bits/stdc++.h>
using namespace std;
int m,n,mr,mc;
int numb[51][51];
char a[1005][1005];
char ss[7][8]={
	' ',' ',' ',' ',' ',' ',' ',' ',
	' ',' ',' ','+','-','-','-','+',
	' ',' ','/',' ',' ',' ','/','|',
	' ','+','-','-','-','+',' ','|',
	' ','|',' ',' ',' ','|',' ','+',
	' ','|',' ',' ',' ','|','/',' ',
	' ','+','-','-','-','+',' ',' '
};//存块
void putinto(int y,int x){
	int t1,t2;
	for(int i=x;i<=x+5;i++){
		for(int j=y;j<=y+6;j++){
			if(i>mr)mr=i;
			if(j>mc)mc=j;
            //这是更新边界,方便进行输出
			t1=6-i+x;
			t2=j-y+1;
			if((t1==1&&(t2==1||t2==2))||(t1==2&&t2==1))continue;
			if((t1==5&&t2==7)||(t1==6&&(t2==6||t2==7)))continue;
			a[i][j]=ss[6-i+x][j-y+1];
		}
	}
}
int main(){
	cin>>m>>n;
	for(int i=1;i<=900;i++){
		for(int j=1;j<=900;j++){
			a[i][j]='.';
		}
	}//将a数组背景设置为.
	for(int i=m;i>=1;i--){
		for(int j=1;j<=n;j++){
			cin>>numb[i][j];
		}
	}//输入
	for(int i=m;i>=1;i--){
		for(int j=1;j<=n;j++){
			for(int k=1;k<=numb[i][j];k++){
				putinto((i-1)*2+1+(j-1)*4,(i-1)*2+1+(k-1)*3);//这是计算出这个立方体在a图中的位置,为了更方便,我们把整张a图倒过来进行putinto
			}
		}
	}
	for(int i=mr;i>=1;i--){
		for(int j=1;j<=mc;j++){
			cout<<a[i][j];
		}
		cout<<endl;
	}//输出
	return 0;
} 

两个都是很简单的大模拟,简直就是一眼出答案(然而我总共调了将近40分钟)

完结撒花~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值