Uva 101 The Blocks Problem(不定长数组 vector)

本文介绍了一种使用C++中的vector容器来模拟堆叠木块的操作方法,包括移动、放置等具体步骤,并通过自定义函数实现了代码复用。

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

本题思路上没有什么难点,直接模拟操作便可。
难点在于如何用vector模拟出这些操作。通过这题,可以对vector的用法有所理解。
在框架上,由于不同操作有很多相同之处,可将它们提炼出来,故本题用到很多自定义函数,算是自顶向下的求解。但是由于我的思维不够成熟,共同点的提炼较浅,更简洁的方法参见《算法竞赛入门经典》P110.

//#define LOCAL

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

const int maxn=30;
vector <int>pile[maxn];
int N,a,b,pileA,pileB;

int find_pile(int c){     //找到木块c所在堆 
    for(int i=0;i<N;i++)
        for(int j=0;j<pile[i].size();j++)
            if(pile[i][j]==c) return i;
}

void get_pileAB(){    
    pileA=find_pile(a);
    pileB=find_pile(b);
}

void recover(int pC,int c){   //将c所在堆c纸上的木块还原,未还原c 
    int s=pile[pC].size()-1;
    int bloc=pile[pC][s];
    while((bloc!=c)&&s>=0){
        pile[bloc].push_back(bloc);
        pile[pC].pop_back();
        bloc=pile[pC][--s];
    }
}

void move_pile(int p1,int p2,int c){   //将c及以上木块从c所在堆p1移到p2 
    int height; 
    for(height=0;height<pile[p1].size();height++)
        if(pile[p1][height]==c) break;
    for(int i=height;i<pile[p1].size();i++) 
        pile[p2].push_back(pile[p1][i]);
    pile[p1].resize(height);//这条语句的应用避免了在写一重循环,利用pop_back()依次删除
}

void move_a_onto_b(){
    recover(pileA,a);
    recover(pileB,a);
    pile[pileB].push_back(a);   //单独处理a 
    pile[pileA].pop_back();
}

void move_a_over_b(){
    recover(pileA,a);
    pile[pileB].push_back(a);
    pile[pileA].pop_back();
}

void pile_a_onto_b(){
    recover(pileB,b);
    move_pile(pileA,pileB,a);
} 

void pile_a_over_b(){
    move_pile(pileA,pileB,a);
}

void print(){    //输出 
    for(int i=0;i<N;i++){
        printf("%d:",i);
        if(pile[i].empty()) printf("\n");
        else{
            for(int j=0;j<pile[i].size();j++)
                printf(" %d",pile[i][j]);
            printf("\n");
        }
    }
}


int main(){
    #ifdef LOCAL
    freopen("data.in","r",stdin);
    #endif
    scanf("%d",&N);
    for(int i=0;i<N;i++) pile[i].push_back(i);
    string s1,s2;
    while(cin>>s1>>a>>s2>>b){
        if(s1=="quit") break;  //这条语句的位置有讲究,不能放在下面的那个地方     
        if(a==b) continue;
        get_pileAB();
        if(pileA==pileB)continue;
//      if(s1=="quit") break;    //pileA和B是全局变量,如果上一条语句pileA和pileB相等,接下来是quit,如果放在这里,这quit将不会起到作用。 
        if((s1=="move")&&(s2=="onto")) move_a_onto_b();
        else if((s1=="move")&&(s2=="over")) move_a_over_b();
        else if((s1=="pile")&&(s2=="onto")) pile_a_onto_b();
        else if((s1=="pile")&&(s2=="over")) pile_a_over_b();
    }
    print();
    return 0;
}

注意点:1.vector不定长数组的用法:
1)定义vector数组:

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

2)获取vector的长度,直接访问里面的元素(和普通数组一样)

int find_pile(int c){     //找到木块c所在堆 
    for(int i=0;i<N;i++)
        for(int j=0;j<pile[i].size();j++)
            if(pile[i][j]==c) return i;
}

3)向最后添加元素,删除最后的元素

    pile[pileB].push_back(a);   
    pile[pileA].pop_back();

这里,通过实验,发现似乎不可以以直接赋值的方式赋值(或者说即使赋值了但不可访问)给还未“开辟”的单元格,但是可以直接访问、修改已经用push_back()开辟的单元格。如下:

int main(){
    vector<int>pile;
    pile.push_back(1);
    pile.push_back(2);
    pile[1]=3;    //修改已开辟的单元格,修改成功且可以被访问
    pile[2]=5;   //不用push_back()在末尾添加元素,可赋值但是无法被访问
    pile[8]=9;   //直接赋值较远的单元格,可赋值但无法被访问
    printf("%d  %d   %d   %d\n",pile.empty(), pile[1],pile[2],pile[8]); 
    for(int i=0;i<pile.size();i++) printf("%d\n",pile[i]);
}

结果:

0 3 5 9
1
3

4)重新改变数组大小

pile[p1].resize(height);

这条语句的应用见上面代码,可用这条语句实现后面一大堆数据不要的功能

通过实验,resize()可能只是将vector中更改了某些变量,如与size有关的变量,但是并没有消除元素,释放空间。

int main(){
    vector<int>pile;
    pile.push_back(1);
    pile.push_back(2);
    pile.push_back(3);
    pile.push_back(4);
    pile.push_back(5);
    pile.resize(3);
    printf("%d\n",pile[4]);
}

结果:

5

结合两个实验,可以认为一些元素可以存在但是可能不被vector认可,即在逻辑上已经不是vector的一部分了。

5)判断是否为空

if(pile[i].empty()) printf("\n");

若为空,返回1,否则返回0。

2.输入问题
本题需要输入指令而且需要从指令中提炼出数字信息,一开始的想法是命令长度一样,想定义字符数组
char cmd[13],但是含有空格、quit的与其他的不一致给字符串的输入造成了困难(不知道用哪个函数、怎么用)。
借鉴本题中的输入方法,利用cin和string。

string s1,s2;
    while(cin>>s1>>a>>s2>>b){……}  //cin可以连续输入到不同变量中

通过接触了getchar()和上面的方式,请意识到并接受:
1)getchar():虽然键盘上是一次性输入的,但是是一个一个字符接收的。
2) 看上去是一个整体的变量(一行字符串等)可以拆分成不同的部分,用不同的变量来储存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值