题解 The Blocks Problem(UVa101)紫书P110vector的应用

紫书P110;vector的应用;UVa101 The Blocks Problem

Vjudge题目地址请移步此处

题目大意:

输入n (0<n<25),得到编号为0到n-1的木块,分别摆放在顺序排列编号为0到n-1的位置。现对这些木块进行操作,操作分为四种。

  • move a onto b:把木块a、b上的木块放回各自的原位,再把a放到b上;
  • move a over b:把a上的木块放回各自的原位,再把a发到含b的堆上;
  • pile a onto b:把b上的木块放回各自的原位,再把a连同a上的木块移到b上;
  • pile a over b:把a连同a上木块移到含b的堆上。

当输入quit时,结束操作并输出0~n-1的位置上的木块情况。

Sample Input
10
move 9 onto 1
move 8 over 1
move 7 over 1
move 6 over 1
pile 8 over 6
pile 8 over 5
move 2 over 1
move 4 over 9
quit

Sample Output
0: 0
1: 1 9 2 4
2:
3: 3
4:
5: 5 8 7 6
6:
7:
8:
9:

题目分析(思路依据紫书):

数据结构选择:每个单元格内block的数目是动态的,固可以采用vector模拟一个单元格,而单元格总共有n个,n值确定,所以可以开一个每个单元都是vector的数组:vector<int> pile[26]

算法设计:题目涉及整段数据与单个数据的移动,且n最大只有25,固采用模拟的方法时间复杂度完全够用。
而模拟的过程涉及两个步骤:<1. 复原block <2. 移动block;
分析题目中四条指令:
move需要将a上方block全部复原,单独移动a;
pile不需要将复原a上方block,需要整段移动;
onto需要将b上方block全部复原,要求a与b相邻;
over不需要复原b上方block,再移动a或者整段。
分析四条指令的异同点且结合先复原后移动的顺序,刘汝佳老师巧妙地进行了以下处理(个别地方与原代码不同):

//pa和pb为a和b的数组下标,ha和hb为a和b的vector下标
if(order1=="move") clear_above(pa,ha);//将pa,ha位置上方的block复原
if(order2=="onto") clera_above(pb,hb);//将pb,hb位置上方的block复原
pile_onto(pa,ha,pb);//将pa,ha位置及其上方的block移动至pb顶端

模块设计:至此,程序的基本框架为:预处理–输入与初始化–模拟–输出–return 0;

代码:
#include<cstdio>
#include<iostream>
#include<string>
#include<vector>
using namespace std;

int n,a,b;
string order1,order2;
vector<int> pile[26];

void find_block(int num,int& h,int& p);
void clear_above(int h,int p);
void pile_onto(int p1,int h1,int p2);
void print();

int main()
{
	 //读入与初始化 
	 scanf("%d",&n);
	 for(int i=0;i<n;i++) pile[i].push_back(i);
	 //模拟 
	 while(cin>>order1>>a>>order2>>b)
	 {
	 	 int ha,hb,pa,pb;
	 	 find_block(a,ha,pa);
	 	 find_block(b,hb,pb);
	 	 if(pa==pb) continue;
	 	 if(order1=="move") clear_above(ha,pa);
	 	 if(order2=="onto") clear_above(hb,pb);
	 	 pile_onto(pa,ha,pb);
	 	 //print();
	 }
	 //输出
	 print();
	 return 0;
}

void find_block(int num,int& h,int& p)
{
	 for(p=0;p<n;p++)
	 	 for(h=0;h<pile[p].size();h++)
	 	 	 if(pile[p][h]==num) return ;
}

void clear_above(int h,int p)
{
	 for(int i=h+1;i<pile[p].size();i++)
	 	 pile[pile[p][i]].push_back(pile[p][i]);
	 pile[p].resize(h+1);
	 return ;
}

void pile_onto(int p1,int h1,int p2)
{
	 for(int i=h1;i<pile[p1].size();i++)
	 	 pile[p2].push_back(pile[p1][i]);
	 pile[p1].resize(h1);
	 return ;
}

void print()
{
	 for(int i1=0;i1<n;i1++)
	 {
	 	 printf("%d:",i1);
	 	 for(int i2=0;i2<pile[i1].size();i2++) printf(" %d",pile[i1][i2]);
	 	 printf("\n");
	 }
}

要点与细节总结:
  1. 刘汝佳老师在计算a块与b块所在的h与p时,采用了引用传值的方法,一个函数同时计算了两个局部变量:
void find_block(int num,int& h,int& p)
  1. 数据结构的选择vector数组,题目中使用到的函数有v.size(); v.resize(); v.push_back();
  2. 提取四个指令的共同点,设计出两个函数减少重复代码。
更新于2020.6.22
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值