相信很多第一眼看到这两道题数据和题目的人都会想到:
学霸题
数正方体
头顶标数法
从上往下数
这两道题乍一看难度,哎呀!一黄一绿,简直是美丽极了,对小蒟蒻来说似乎不是很友好,但实际上仔细想想也不难,我们先从绿色的数正方体开始讲(主要因为我先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分钟)
完结撒花~