算法练习(5)———木块问题

木块问题:

描述:

从左到右有n个木块,编号为0~n-1,要求模拟以下4种操作(下面的a和b都是木块编

号)。

move a onto b:把a和b上方的木块全部归位,然后把a摞在b上面。

move a over b:把a上方的木块全部归位,然后把a放在b所在木块堆的顶部。

pile a onto b:把b上方的木块全部归位,然后把a及上面的木块整体摞在b上面。

pile a over b:把a及上面的木块整体摞在b所在木块堆的顶部。

遇到quit时终止一组数据。a和b在同一堆的指令是非法指令,应当忽略。

例:

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:

 

———————————————————————————————————————————


题目分析:

刚开始看到题目时,一脸懵逼,完全不懂题目什么意思,后来在看到博主[蓝冰lanbing]的分析 +自己多看几遍题目,细细品味才看懂。

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

再回看下题目:

1、从左到右有n个木块,编号为0~n-1

        意思如图(假设有10个木块):

        最开始,10个木块分成10堆,编号从0~9.

2、move 9 onto 1

        把9和1上方的木块全部归位,然后把9摞在1上

3、第三点还有注意的是:over b是找到b所在的那堆,并放在那堆的上面

        //在这里,我只想说一句,对于语言文字理解能力差的我,看懂题目真的不容易啊

声明:参考CSDN博主「蓝冰lanbing」

原文链接:https://blog.csdn.net/weixin_43827530/article/details/100671692


代码部分:

注意:这里输入一共有4种指令,但如果完全独立地处理各指令,代码就会变得冗长而且易错。更好的方法是提取出指令之间的共同点,编写函数以减少重复代码。

1、找木块a所在的pile和height ,以引用形式返回调用者

void find_block(int a, int& p, int& h) {

    for (p = 0;p < n; p++)

        for(h =0;h<pile[p].size();h++)

            if (pile[p][h] == a) return;
}

2、把第P堆高度为h的木块上方的所有木块移回原位

void clear_above(int p, int h) {

    for (int i = h + 1; i < pile[p].size();i++) {

        int b = pile[p][i];

        pile[b].push_back(b);  //把木块b放回原位

    }

    pile[p].resize(static_cast<std::vector<int, std::allocator<int>>::size_type>(h) + 1);   //pile只应保留下标0~h的元素

}

//(因为我用的是vs2022版,所以加了static_cast<std::vector<int, std::allocator<int>>::size_type>,其他版本可能只需写pile[p].resize(h+1)即可)

3、把第p堆高度为h及其上方的木块整体移动到p2堆的顶部

void pile_onto(int p, int h, int p2) {

    for (int i = h;i < pile[p].size();i++) {

        pile[p2].push_back(pile[p][i]);

    pile[p].resize(h);

    }

}

4、打印函数

void pile_onto(int p, int h, int p2) {

    for (int i = h;i < pile[p].size();i++) {

        pile[p2].push_back(pile[p][i]);

    pile[p].resize(h);

    }

}

总代码:

#include <cstdio>

#include <iostream>

#include <string>

#include <vector>

using namespace std;



const int maxn = 30;

int n;

vector<int> pile[maxn];   //每一个pile[i]都是都是一个vector



//找木块a所在的pile和height ,以引用形式返回调用者

void find_block(int a, int& p, int& h) {

    for (p = 0;p < n; p++)

        for(h =0;h<pile[p].size();h++)

            if (pile[p][h] == a) return;

   

}



//把第P堆高度为h的木块上方的所有木块移回原位

void clear_above(int p, int h) {

    for (int i = h + 1; i < pile[p].size();i++) {

        int b = pile[p][i];

        pile[b].push_back(b);  //把木块b放回原位

    }

    pile[p].resize(static_cast<std::vector<int, std::allocator<int>>::size_type>(h) + 1);   //pile只应保留下标0~h的元素

}



//把第p堆高度为h及其上方的木块整体移动到p2堆的顶部

void pile_onto(int p, int h, int p2) {

    for (int i = h;i < pile[p].size();i++) {

        pile[p2].push_back(pile[p][i]);

    pile[p].resize(h);

    }

}



void print() {

    for (int i = 0;i < n;i++) {

        printf("%d:", i);

        for (int j = 0;j < pile[i].size();j++) {

            printf(" %d", pile[i][j]);

        }

        printf("\n");

    }

}





int main()

{

    int a, b;

    cin >> n;

    string s1, s2;

    for (int i = 0;i < n;i++)

        pile[i].push_back(i);

    while (cin >> s1 >> a >> s2 >> b ) {//&& s1!= "quit"

        int pa, pb =0, ha, hb=0;

        find_block(a, pa, ha);

        find_block(b, pb, hb);

        if (pa == pb) continue;//非法指令

        if (s2 == "onto") clear_above(pb, hb);

        if (s1 == "move") clear_above(pa, ha);

        pile_onto(pa, ha, pb);

    }

    print();

    return 0;

}

最后再对知识点进行一个补充: 

知识补充:
        (1)static_cast   

        显性类型强制转换,和C语言学习时的显性意义一样,但是编译器会对此类型转换进行检查

        一般来说,编译器隐式执行的任何类型转换都可以由static_cast显式完成。static_cast可以用来将枚举类型转换成整型,或者整型转换成浮点型。也可以用来将指向父类的指针转换成指向子类的指针。做这些转换前,你必须确定要转换的数据确实是目标类型的数据,因为static_cast不做运行时的类型检查以保证转换的安全性。也因此,static_cast不如dynamic_cast安全。对含有二义性的指针,dynamic_cast会转换失败,而static_cast却直接且粗暴地进行转换,这是非常危险的。

        还有要注意的是,他不能转换掉expression的const、volatile、或者__unaligned属性,同样也不能用来去掉static属性。

        C++中的sta        tic_cast执行非多态的转换,用于代替C中通常的转换操作。对于我们的static_cast转换符,他不仅可以应用到指针和引用上,而且还可以应用到基础数据结构和对象上。

--------------------------------------------

声明:来自CSDN博主「Citronnelle2」

原文链接:https://blog.csdn.net/zhouwei1221q/article/details/44978361

(2)std::allocator 

        标准库中包含一个名为allocator的类,允许我们将分配和初始化分离。使用allocator通常会提供更好的性能和更灵活的内存管理能力。

        new有一些灵活性上的局限,其中一方面表现在它将内存分配和对象构造组合在了一起。类似的,delete将对象析构和内存释放组合在了一起。我们分配单个对象时,通常希望将内存分配和对象初始化组合在一起。因为在这种情况下,我们几乎肯定知道对象应有什么值。当分配一大块内存时,我们通常计划在这块内存上按需构造对象。在此情况下,我们希望将内存分配和对象构造分离。这意味着我们可以分配大块内存,但只在真正需要时才真正执行对象的创建操作(同时付出一定开销)。一般情况下,将内存分配和对象构造组合在一起可能会导致不必要的浪费。

        标准库allocator类定义在头文件memory中,它帮助我们将内存分配和对象构造分离开来。它提供一种类型感知的内存分配方法,它分配的内存是原始的、未构造的。类似vector,allocator是一个模板。为了定义一个allocator对象,我们必须指明这个allocator可以分配的对象类型。当一个allocator对象分配内存时,它会根据给定的对象类型来确定恰当的内存大小和对齐位置。

————————————————

声明:来自CSDN博主「fengbingchun」

原文链接:https://blog.csdn.net/fengbingchun/article/details/78943527

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值