Uva 101 The Blocks Problem(模拟)

 题目链接:https://vjudge.net/problem/UVA-101

题意

有 0 ~ n - 1 个木块,一共有四种指令:

  • 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 所在的木块堆的顶部。

如果 a b 在同一木块堆中则视为无效指令。

思路

从四种指令中抽象出两个基本操作:

  • clear above:把 a 上方的木块全部复位
  • move:把 a 以及上方的木块放在 b 所在木块堆的顶部

然后考虑如何快速查找某一木块所在的木块堆以及在其中的高度,可以用一个一对二的映射,将每个木块推入新堆时更新。

代码

初始代码

#include <bits/stdc++.h>
using namespace std;

vector<vector<int>> v;
map<int, pair<int, int>> mp;

void update(int a, int b) {//把 b 推入木块堆 a 中的同时更新其所在的木块堆和高度
    mp[b].first = a;
    mp[b].second = v[a].size();
    v[a].push_back(b);
}

void clear_above(int a) {//将 a 上面的木块复位
    int vec = mp[a].first;
    int h = mp[a].second;
    for (int i = h + 1; i < v[vec].size(); i++) {
        update(v[vec][i], v[vec][i]);
    }
    v[vec].resize(h + 1);
}

void move(int a, int b) {//将 a 以及 a 上面的木块放在 b 所在木块堆顶部
    int vec = mp[a].first;
    int h = mp[a].second;
    int vec_b = mp[b].first;
    for (int i = h; i < v[vec].size(); i++) {
        update(vec_b, v[vec][i]);
    }
    v[vec].rresize(h);
}

int main() {
    int n; cin >> n;
    v.resize(n);
    for (int i = 0; i < n; i++) update(i, i);
    string s1;
    while (cin >> s1 and s1 != "quit") {
        int a, b; string s2;
        cin >> a >> s2 >> b;
        if (mp[a].first == mp[b].first) continue;
        if (s1 == "move") {
            if (s2 == "onto") {//move_onto
                clear_above(a);
                clear_above(b);
                move(a, b);
            } else {//move_over
                clear_above(a);
                move(a, b);
            }
        } else {
            if (s2 == "onto") {//pile_onto
                clear_above(b);
                move(a, b);
            } else {//pile_over
                move(a, b);
            }
        }
    }
    for (int i = 0; i < n; i++) {
        cout << i << ":";
        for (int x : v[i]) cout << ' ' << x;
        cout << "\n";
    }
}

优化

不难发现:

  • s1 为 “move” 时有 clear_above(a)
  • s2 为 "onto" 时有 clear_above(b)
  • 四种指令都有 move(a, b)

优化代码

#include <bits/stdc++.h>
using namespace std;

vector<vector<int>> v;
map<int, pair<int, int>> mp;

void update(int a, int b) {//把 b 推入木块堆 a 中的同时更新其所在的木块堆和高度
    mp[b].first = a;
    mp[b].second = v[a].size();
    v[a].push_back(b);
}

void clear_above(int a) {//将 a 上面的木块复位
    int vec = mp[a].first;
    int h = mp[a].second;
    for (int i = h + 1; i < v[vec].size(); i++) {
        update(v[vec][i], v[vec][i]);
    }
    v[vec].resize(h + 1);
}

void move(int a, int b) {//将 a 以及 a 上面的木块放在 b 所在木块堆顶部
    int vec = mp[a].first;
    int h = mp[a].second;
    int vec_b = mp[b].first;
    for (int i = h; i < v[vec].size(); i++) {
        update(vec_b, v[vec][i]);
    }
    v[vec].resize(h);
}

int main() {
    int n; cin >> n;
    v.resize(n);
    for (int i = 0; i < n; i++) update(i, i);
    string s1;
    while (cin >> s1 and s1 != "quit") {
        int a, b; string s2;
        cin >> a >> s2 >> b;
        if (mp[a].first == mp[b].first) continue;
        if (s1 == "move") clear_above(a);
        if (s2 == "onto") clear_above(b);
        move(a, b);
    }
    for (int i = 0; i < n; i++) {
        cout << i << ":";
        for (int x : v[i]) cout << ' ' << x;
        cout << "\n";
    }
}

 

posted @ 2020-04-22 20:37  Kanoon  阅读(147)  评论(0)    收藏  举报