鱼香rose'Blog

The Blocks Problem

本题是一道模拟题,但个人感觉挺有意思的(思路很明确,但是WA了好几发才过),因此来讲一讲思路。

题面

题面PDF
在这里插入图片描述

样例输入

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

样例输出

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

题意简述

初始时从左到右有 \(n\) 个木块,编号分别为 \(0 \ldots n-1\),要求实现下列四种操作:

  1. move a onto b : 把 \(a\)\(b\) 上方的木块归位,然后把 \(a\) 放到 \(b\) 上面。
  2. move a over b : 把 \(a\) 上方的木块归位,然后把 \(a\) 放在 \(b\) 所在木块堆的最上方。
  3. pile a onto b : 把 \(b\) 上方的木块归位,然后把 \(a\) 及以上的木块坨到 \(b\) 上面。
  4. pile a over b : 把 \(a\) 及以上的木块坨到 \(b\) 的上面。

一组数据的结束标志为 quit,如果有非法指令(如 \(a\)\(b\) 在同一堆),无需处理。

输出:所有操作输入完毕后,从左到右,从下到上输出每个位置的木块编号。

思路

通过观察上面四种操作,我们会发现,这四种操作可以拆分为三种:

  • move \(x\):将木块x上面木块归位。
  • pile$ x$:无操作。
  • onto \(x\):将木块x上面的木块归位。
  • over \(x\):无操作。

然后我们还会发现,无论哪个操作,最终都会将a放在b上边。

因此,上边的操作就转换为了两类:归位合并。然后我们实现这两种操作即可。

而这两种操作显然用\(vector\)容器比较方便,因此我们尝试用\(vector\)来实现。标程里有详细代码+注释,请放心食用。

标程

#include<bits/stdc++.h>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
#define LL long long 
#define ULL unsigned long long 
#define PII pair<int, int>
#define lowbit(x) (x & -x)
#define Mid ((l + r) >> 1)
#define ALL(x) x.begin(), x.end()
#define endl '\n'
#define fi first 
#define se second

const int INF = 0x7fffffff;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;

vector<vector<int>> a(30);	//用二维vector,第一维表示原位置,第二维表示当前位置堆的木块
int n, x1, x2;

PII find(int x) {							//找到需要进行操作的木块的位置
    for(int i = 0; i < n; i ++ )
        for(int j = 0; j < a[i].size(); j ++ )
            if(a[i][j] == x) return {i, j};	//第i堆的第j个
}

void homing(PII i) {					//归位操作
    while(a[i.fi].size() - 1 > i.se) {
        int t = a[i.fi].back();
        a[t].push_back(t);				//将其后边的全都归位,本身不动
        a[i.fi].pop_back();
    }
}

void merge(PII i, PII j) {				//合并操作
    for(int k = i.se; k < a[i.fi].size(); k ++ ) {
        int t = a[i.fi][k];
        a[j.fi].push_back(t);
    }
    a[i.fi].resize(i.se);				//将其大小设为i.se,相当于舍弃后面的元素
}

void Solved() {
    cin >> n;
    string s1, s2;

    for(int i = 0; i < n; i ++ ) a[i].push_back(i);//初始化
    while(cin >> s1) {
        if(s1 == "quit") break;

        cin >> x1 >> s2 >> x2;
        PII y1 = find(x1), y2 = find(x2);	//如果在同一堆的话是没办法进行操作的

        if(y1.fi == y2.fi) continue;
        if(s2 == "onto") homing(y2);		//需要先对b进行操作
        if(s1 == "move") homing(y1);
        merge(y1, y2);
    }
    
    for(int i = 0; i < n; i ++ ) {//输出
        cout << i << ":";
        for(int j : a[i]) cout << " " << j;
        cout << endl;
    }
}

signed main(void) {
    IOS

    int ALL = 1; 
    // cin >> ALL;
    while(ALL -- ) Solved();
    // cout << fixed;//强制以小数形式显示
    // cout << setprecision(n); //保留n位小数

    return 0;
}
posted @ 2026-01-15 21:53  鱼香_rose  阅读(0)  评论(0)    收藏  举报