入门经典_Chap06_例题[一]:队列,栈,链表的数组实现

本文通过多个UVA题目,展示了如何使用数组、链表等数据结构解决实际问题,涉及并发模拟、铁路调度、矩阵链乘等问题。

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

前言

    这一章的终极目的是巩固数据结构,尽可能地使用数组实现所有的数据结构,包括队列,栈,链表,二叉树等

题解如下

UVA - 210_Concurrency Simulator

思路

    (书上的原话)你的任务是模拟n个程序(按输入顺序编号为1~n)的并行执行。每个程序包含不超过25条语句,格式一共有5种:var = constant(赋值);print var(打印);lock;unlock;end。
    变量用单个小写字母表示,初始为0,为所有程序公有(因此在一个程序里对某个变量赋值可能会影响另一个程序)。常数是小于100的非负整数。
    每个时刻只能有一个程序处于运行态,其他程序均处于等待态。上述5种语句分别需要t1、t2、t3、t4、t5单位时间。运行态的程序每次最多运行Q个单位时间(称为配额)。当一个程序的配额用完之后,把当前语句(如果存在)执行完之后该程序会被插入一个等待队列中,然后处理器从队首取出一个程序继续执行。初始等待队列包含按输入顺序排列的各个程序,但由于lock/unlock语句的出现,这个顺序可能会改变。
    lock的作用是申请对所有变量的独占访问。lock和unlock总是成对出现,并且不会嵌套。lock总是在unlock的前面。当一个程序成功执行完lock指令之后,其他程序一旦试图执行lock指令,就会马上被放到一个所谓的阻止队列的尾部(没有用完的配额就浪费了)。当unlock执行完毕后,阻止队列的第一个程序进入等待队列的首部。输入n, t1, t2, t3, t4, t5, Q以及n个程序,按照时间顺序输出所有print语句的程序编号和结果。

    使用队列模拟,要用到双端队列,这里用数组模拟的, 也可以使用STL里的deque
    复杂点在于字符串的处理,和lock的处理

代码

#include <algorithm>
#include <iostream>
#include <sstream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cstdio>
#include <cmath>
#define met(a,b) memset(a, b, sizeof(a));
#define IN freopen("in.txt", "r", stdin);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e3 + 100;
const int INF = 0x7fffffff;

int n, a[6], Q;
string s, str;
vector<string> v[maxn];
int curID[maxn], val[30];
bool lock;

int qw[maxn], wft, wrr;
int qd[maxn], dft, drr;

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    int t; cin >> t;
    while(t--) {
        wft = wrr = maxn/2; dft = drr = maxn/2;
        scanf("%d", &n); for(int i = 0; i < 5; ++i) scanf("%d", &a[i]); scanf("%d", &Q);
        for(int i = 1; i <= n; ++i) {
            v[i].clear();
            while(getline(cin, s)) {
                if(s == "") continue;
                v[i].push_back(s);
                if(s == "end") break;
            }
            qw[wrr++] = i;
        }

        met(curID, 0); met(val, 0); lock = 0;
        while(wrr > wft) {
            int cur = qw[wft++];
            int L = Q, tot = v[cur].size();
            bool flag = 0;

            while(L > 0) {
                str = v[cur][curID[cur]];
                if(str[2] == '=') {
                    str[2] = ' ';
                    stringstream ss(str);
                    char aa; int b;
                    ss >> aa >> b;
                    val[aa - 'a'] = b;
                    L -= a[0];
                }
                else if(str[0] == 'p') {
                    printf("%d: %d\n", cur, val[str[str.size()-1]-'a']);
                    L -= a[1];
                }
                else if(str[0] == 'l') {
                    if(lock) {
                        qd[drr++] = cur; flag = 1; break;
                    }
                    lock = 1;
                    L -= a[2];
                }
                else if(str[0] == 'u') {
                    if(lock) {
                        if(drr>dft) qw[--wft] = qd[dft++];
                        lock = 0;
                    }
                    L -= a[3];
                }
                else { flag = 1; break; }
                ++curID[cur];
            }
            if(! flag) qw[wrr++] = cur;
        }


        if(t) printf("\n");
    }

    return 0;
}

UVA - 514_ Rails

思路

模拟栈的水题,不解释

代码

#include <algorithm>
#include <iostream>
#include <sstream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cstdio>
#include <cmath>
#define met(a,b) memset(a, b, sizeof(a));
#define IN freopen("in.txt", "r", stdin);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e3 + 100;
const int INF = 0x7fffffff;

int n, a[maxn];
int stake[maxn];

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    while(scanf("%d", &n) == 1 && n) {
        while(scanf("%d", &a[0]) == 1 && a[0]) {
            for(int i = 1; i < n; ++i) scanf("%d", &a[i]);
            int cur = 1, top = 0;

            bool ok = 1;
            for(int i = 0; i < n; ++i) {
                if(top > 0 && a[i] == stake[top]) {
                    --top; continue;
                }
                else {
                    while(cur <= n && a[i] != cur) stake[++top] = cur, ++cur;
                    if(cur > n) { ok = 0; break; }
                    else ++cur;
                }
            }
            if(ok) printf("Yes\n");
            else printf("No\n");
        }
        printf("\n");


    }

    return 0;
}

UVA - 442_Matrix Chain Multiplication

思路

    输入n个矩阵的维度和一些矩阵链乘表达式,输出乘法的次数。如果乘法无法进行,输出error。
    假定A是m * n矩阵,B是n * p矩阵,那么AB是m * p矩阵,乘法次数为m * n * p。如果A的列数不等于B的行数,则乘法无法进行。
    例如,A是50 * 10的,B是10 * 20的,C是20 * 5的,则(A(BC))的乘法次数为10 * 20 * 5(BC的乘法次数)+ 50 * 10 * 5((A(BC))的乘法次数)= 3500。

    栈的应用:栈可以用于解析表达式!

代码

#include <algorithm>
#include <iostream>
#include <sstream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cstring>
#include <cstdio>
#include <cmath>
#define met(a,b) memset(a, b, sizeof(a));
#define IN freopen("in.txt", "r", stdin);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e3 + 100;
const int INF = 0x7fffffff;

int n, a, b;
char c;
string str;

struct node {
    int r, c;
    node (){}
    node (int a, int b):r(a), c(b){}
}e[30];

stack<node> s;

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    cin >> n;
    for(int i = 0; i < n; ++i) {
        getchar();
        scanf("%c %d%d", &c, &a, &b);
        e[c-'A'] = node(a, b);
    }

    while(cin >> str) {
        int len = str.length(), ans = 0;
        for(int i = 0; i < len; ++i) {
            if(str[i] == '(') { }
            else if(str[i] == ')' ) {
                node ta = s.top(); s.pop();
                node tb = s.top(); s.pop();
                if(ta.r != tb.c) { ans = -1; break; }
                ans += tb.r*ta.r*ta.c;
                s.push(node(tb.r, ta.c));
            }
            else s.push(e[str[i]-'A']);
        }

        if(ans == -1) printf("error\n");
        else printf("%d\n", ans);
    }

    return 0;
}

UVA - 11988_Broken Keyboard (a.k.a. Beiju Text)

思路

    链表的数组实现,实用+方便
    有一点个人领悟,使用链表的时候所有的数组最好下标都从1开始,给头指针留有余地。

代码

#include <algorithm>
#include <iostream>
#include <sstream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cstdio>
#include <cmath>
#define met(a,b) memset(a, b, sizeof(a));
#define IN freopen("in.txt", "r", stdin);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e6 + 100;
const int INF = 0x7fffffff;

char s[maxn];

int nxt[maxn];

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    while(cin >> s+1) {
        nxt[0] = 0;
        int cur = 0, last = 0;

        int len = strlen(s+1);
        for(int i = 1; i <= len; ++i) {
            char c = s[i];
            if(c == '[') cur = 0;
            else if(c == ']') cur = last;
            else {
                nxt[i] = nxt[cur];
                nxt[cur] = i;
                if(cur == last) last = i;
                cur = i;
            }
        }

        for(int i = nxt[0]; i != 0; i = nxt[i]) printf("%c", s[i]);
        printf("\n");
    }

    return 0;
}

UVA - 12657_Boxes in a Line

思路

    双向链表的裸题,不过我写这道题的时候感觉蛮坑的
    主要是遍历的时候,最好根据元素个数来遍历,不要像单链表那样直接使用i = next[i]来遍历,因为它有一个循环的过程,搞不好会超时。
    然后在插入或者删除的时候,最好将会改变的东西先存下来,以防后面改其它的东西的时候它也跟着变了
    还有重要的一点,交换的时候两个物品相邻的情况要特判一下,不要想当然。

代码

#include <algorithm>
#include <iostream>
#include <sstream>
#include <utility>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <cstring>
#include <cstdio>
#include <cmath>
#define met(a,b) memset(a, b, sizeof(a));
#define IN freopen("in.txt", "r", stdin);
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int maxn = 1e5 + 100;
const int INF = 0x7fffffff;

int n, m, x, y, opt;
int nxt[maxn], pre[maxn];
bool isRev;

void combine(int i, int j) {
    if(i == j) return;
    nxt[i] = j; pre[j] = i;
}

void init() {
    for(int i = 0; i <= n; ++i) combine(i, (i+1) % (n+1));
}

int main() {
    #ifdef _LOCAL
    IN;
    #endif // _LOCAL

    int kase = 0;
    while(scanf("%d%d", &n, &m) == 2) {
        init(); isRev = 0;
        for(int i = 0; i < m; ++i) {
            scanf("%d", &opt);
            if(opt == 4) isRev = !isRev;
            else {
                scanf("%d%d", &x, &y);
                if(opt != 3 && isRev) opt = 3 - opt;

                int Px = pre[x], Nx = nxt[x];
                int Py = pre[y], Ny = nxt[y];

                if(opt == 1) {
                    if(x == Py) continue;
                    combine(Px,Nx); combine(Py, x); combine(x, y);
                }
                else if(opt == 2) {
                    if(x == Ny) continue;
                    combine(Px, Nx); combine(y, x); combine(x, Ny);
                }
                else {
                    if(x == Ny) swap(x, y);
                    Px = pre[x], Nx = nxt[x];
                    Py = pre[y], Ny = nxt[y];
                    if(y == Nx) {combine(Px, y); combine(y, x); combine(x, Ny); }
                    else { combine(Px, y); combine(y,Nx); combine(Py, x); combine(x, Ny);}
                }
            }
        }

        LL ans = 0;
        int b = 0;
        for(int i = 1; i <= n; ++i) {
            b = nxt[b];
            if(i%2) ans += b;
        }

        if(isRev && n % 2 == 0) ans = (LL)n*(n+1)/2 - ans;
        printf("Case %d: %lld\n", ++kase, ans);
    }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值