前言
这一章的终极目的是巩固数据结构,尽可能地使用数组实现所有的数据结构,包括队列,栈,链表,二叉树等
题解如下
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;
}