UVa 171 - Car Trialling

Problem

Car trialling requires the following of carefully worded instructions. When setting a trial, the organiser places traps in the instructions to catch out the unwary.

Write a program to determine whether an instruction obeys the following rules, which are loosely based on real car trialling instructions. BOLD-TEXT indicates text as it appears in the instruction (case sensitive), | separates options of which exactly one must be chosen, and .. expands, so A..D is equivalent to A | B | C | D .

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
instruction = navigational | time-keeping | navigational AND time-keeping
navigational = directional | navigational AND THEN directional
directional = how direction | how direction where
how = GO | GO when | KEEP
direction = RIGHT | LEFT
when = FIRST | SECOND | THIRD
where = AT sign
sign = "signwords"
signwords = s-word | signwords s-word
s-word = letter | s-word letter
letter = A..Z | .
time-keeping = record tex2html_wrap_inline61 change
record = RECORD TIME
change = cas TO nnn KMH
cas = CHANGE AVERAGE SPEED | CAS
nnn = digit | nnn digit

digit = 0..9 Note that s-word and nnn are sequences of letters and digits respectively, with no intervening spaces. There will be one or more spaces between items except before a period (.), after the opening speech marks or before the closing speech marks.

Input

Each input line will consist of not more than 75 characters. The input will be terminated by a line consisting of a single #.

Output

The output will consist of a series of sequentially numbered lines, either containing the valid instruction, or the text Trap! if the line did not obey the rules. The line number will be right justified in a field of 3 characters, followed by a full-stop, a single space, and the instruction, with sequences of more than one space reduced to single spaces.

Sample input

1
2
3
4
5
6
7
KEEP LEFT AND THEN GO RIGHT
CAS TO 20 KMH
GO FIRST RIGHT AT "SMITH ST." AND CAS TO 20 KMH
GO 2nd RIGHT
GO LEFT AT "SMITH STREET AND RECORD TIME
KEEP RIGHT AND THEN RECORD TIME
#

Sample output

1
2
3
4
5
6
1. KEEP LEFT AND THEN GO RIGHT
2. CAS TO 20 KMH
3. GO FIRST RIGHT AT "SMITH ST." AND CAS TO 20 KMH
4. Trap!
5. Trap!
6. Trap!

Solution

題目描述:

根據題目給定的規則,將汽車引領的命令句子做合法語句判斷。

題目解法:

根據編譯器的方式,採用 LL(1) 修改題目給定的規則後,要進行建表,但是發現有幾處無法排除的語法規則,之後採用 SLR(1) 來完成。

SLR(1) 是由 LR(0) 加上 follow set 完成。

詳細的運作過程請詳見 wiki 說明,或者是修編譯器。

1
There will be one or more spaces between items except before a period (.), after the opening speech marks or before the closing speech marks.

本題最邪惡的地方在這裡,句號(.)前不可以用空白,前雙引號後不可有空白、後雙引號前不可以有空白。

雖然題目有包含這些 token 的語法產生,但還是用最暴力的方式將句子做基礎的 token 切割。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
#include <stdio.h>
#include <vector>
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <string.h>
#include <ctype.h>
#include <assert.h>
using namespace std;
#define HTMLProduction
// #define DEBUG
class Production {
public:
int label;
string LHS;
vector<string> RHS;
Production(string L = "", vector<string> R = vector<string>(), int l=0) {
LHS = L;
RHS = R;
label = l;
}
bool operator<(const Production &p) const {
if(LHS != p.LHS)
return LHS < p.LHS;
for(size_t i = 0, j = 0; i < RHS.size() && j < p.RHS.size(); i++, j++) {
if(RHS[i] != p.RHS[i])
return RHS[i] < p.RHS[i];
}
return RHS.size() < p.RHS.size();
}
bool operator==(const Production &p) const {
if(LHS != p.LHS || RHS.size() != p.RHS.size())
return false;
for(size_t i = 0, j = 0; i < RHS.size(); i++, j++) {
if(RHS[i] != p.RHS[i])
return false;
}
return true;
}
bool operator!=(const Production &p) const {
return !(*this == p);
}
void print() {
printf("%s -> ", LHS.c_str());
for(size_t i = 0; i < RHS.size(); i++)
printf("%s", RHS[i].c_str());
}
};
class Grammar {
public:
/* LR parsing */
class ConfigurationSet {
public:
class State {
public:
int dot;
vector<string> lookahead;
State(int d=0, vector<string> l=vector<string>()):
dot(d), lookahead(l) {}
bool operator<(const State &x) const {
return dot < x.dot;
}
bool operator!=(const State &x) const {
return dot != x.dot;
}
};
set< pair<Production, State> > configs;
int label;
ConfigurationSet() {
label = 0;
}
/* method */
static ConfigurationSet closure0(ConfigurationSet& s, Grammar& g);
static ConfigurationSet go_to0(ConfigurationSet& s, string X, Grammar& g);
void print(Grammar &g) {
set< pair<Production, State> >::iterator it;
Production p;
for(it = configs.begin(); it != configs.end(); it++) {
p = it->first;
printf("%s ->", p.LHS.c_str());
for(size_t i = 0; i < p.RHS.size(); i++) {
if(i == it->second.dot)
printf("¡E");
printf(" %s ", p.RHS[i].c_str());
}
if(it->second.dot == p.RHS.size())
printf("¡E");
printf(" ,{");
set<string> fset = g.follow_set[p.LHS];
for(set<string>::iterator jt = fset.begin();
jt != fset.end(); jt++) {
if(jt != fset.begin())
cout << ", ";
cout << *jt;
}
printf("}");
puts("");
}
}
bool operator<(const ConfigurationSet &x) const {
if(configs.size() != x.configs.size())
return configs.size() < x.configs.size();
for(set< pair<Production, State> >::iterator it = configs.begin(), jt = x.configs.begin();
it != configs.end(); it++, jt++) {
if(it->first != jt->first)
return it->first < jt->first;
if(it->second != jt->second)
return it->second < jt->second;
}
return false;
// return label < x.label;
}
};
static const string lambda;
set<string> symbols;
string start_symbol;
vector<Production> rules;
/* LL(1) attribute */
map<string, set<string> > first_set;
map<string, set<string> > follow_set;
map<string, bool> derives_lambda;
map<string, map<string, Production> > lltable;
/* LR attribute */
vector<ConfigurationSet> LRstates;
map<int, map<string, int> > go_to_table;
map<int, int> action_table;
/* common method */
static bool isNonterminal(string token);
void buildSymbols();
/* LL(1) method */
map<string, bool> mark_lambda();
void fill_first_set();
void fill_follow_set();
set<string> compute_first(vector<string> rhs);
set<string> get_predict_set(Production p);
void fill_lltable();
void lldriver(queue<string> tokens);
/* LR method*/
void build_CFSM();
void build_action();
void lr0driver(queue<string> tokens);
int slr1driver(queue<string> tokens);
void lalr1driver(queue<string> tokens);
/* homework */
void hw_build_CFSM();
};
/* ------------------------
ConfigurationSet method
-------------------------- */
Grammar::ConfigurationSet Grammar::ConfigurationSet::closure0(ConfigurationSet& s, Grammar& g) {
ConfigurationSet r = s;
bool changes;
string A;
Production P;
int dotPos;
set< pair<Production, State> >::iterator it;
do {
changes = false;
for(it = r.configs.begin(); it != r.configs.end(); it++) {
P = it->first;
dotPos = it->second.dot;
if(dotPos >= P.RHS.size() || P.RHS[dotPos] == Grammar::lambda)
continue;
A = P.RHS[dotPos];
if(Grammar::isNonterminal(A)) {
/* B -> x.Ay */
/* Predict productions with A as the left-hand side */
for(size_t i = 0; i < g.rules.size(); i++) {
if(g.rules[i].LHS == A) {
if(r.configs.find(make_pair(g.rules[i], State(0))) == r.configs.end()) {
r.configs.insert(make_pair(g.rules[i], State(0)));
changes = true;
}
}
}
}
}
} while(changes);
return r;
}
Grammar::ConfigurationSet Grammar::ConfigurationSet::go_to0(ConfigurationSet& s, string X, Grammar& g) {
ConfigurationSet sb;
set< pair<Production, State> >::iterator it;
Production P;
int dotPos;
for(it = s.configs.begin(); it != s.configs.end(); it++) {
P = it->first;
dotPos = it->second.dot;
if(dotPos >= P.RHS.size() || P.RHS[dotPos] == Grammar::lambda)
continue;
if(P.RHS[dotPos] == X) {
State state(dotPos + 1, it->second.lookahead);
sb.configs.insert(make_pair(P, state));
}
}
return closure0(sb, g);
}
/* ------------------------
Grammar method
-------------------------- */
const string Grammar::lambda("l");
set<string> Grammar::compute_first(vector<string> rhs) {
set<string> result;
size_t i;
if(rhs.size() == 0 || rhs[0] == Grammar::lambda) {
result.insert(Grammar::lambda);
} else {
result = first_set[rhs[0]];
for(i = 1; i < rhs.size() &&
first_set[rhs[i-1]].find(Grammar::lambda) != first_set[rhs[i-1]].end(); i++) {
set<string> f = first_set[rhs[i]];
f.erase(Grammar::lambda);
result.insert(f.begin(), f.end());
}
if(i == rhs.size()
&& first_set[rhs[i-1]].find(Grammar::lambda) != first_set[rhs[i-1]].end()) {
result.insert(Grammar::lambda);
} else {
result.erase(Grammar::lambda);
}
}
return result;
}
/*
* please call get_predict_set() after fill_follow_set() and fill_first_set()
*/
set<string> Grammar::get_predict_set(Production p) {
set<string> result;
set<string> rfirst;
rfirst = compute_first(p.RHS);
if(rfirst.find(Grammar::lambda) != rfirst.end()) {
rfirst.erase(Grammar::lambda);
result.insert(rfirst.begin(), rfirst.end());
rfirst = follow_set[p.LHS];
result.insert(rfirst.begin(), rfirst.end());
} else {
result.insert(rfirst.begin(), rfirst.end());
}
return result;
}
/*
*
*/
void Grammar::fill_lltable() {
string A; // nonterminal
Production p;
for(size_t i = 0; i < rules.size(); i++) {
p = rules[i];
A = p.LHS;
set<string> predict_set = get_predict_set(p);
for(set<string>::iterator it = predict_set.begin();
it != predict_set.end(); it++) {
assert(lltable[A].find(*it) == lltable[A].end());
lltable[A][*it] = p;
}
}
}
void Grammar::buildSymbols() {
symbols.clear();
for(size_t i = 0; i < rules.size(); i++) {
symbols.insert(rules[i].LHS);
for(size_t j = 0; j < rules[i].RHS.size(); j++) {
symbols.insert(rules[i].RHS[j]);
}
}
}
bool Grammar::isNonterminal(string token) {
#ifdef HTMLProduction
if(token == Grammar::lambda)
return false;
if(token[0] == '<' && token[token.length() - 1] == '>')
return true;
return false;
#else
if(token == Grammar::lambda)
return false;
for(size_t i = 0; i < token.length(); i++) {
if(isupper(token[i]))
return true;
}
return false;
#endif
}
/* ------------------------
Grammar LL method
-------------------------- */
map<string, bool> Grammar::mark_lambda() {
bool rhs_derives_lambda;
bool changes;
Production p;
derives_lambda.clear();
/* initially, nothing is marked. */
for(size_t i = 0; i < rules.size(); i++) {
derives_lambda[rules[i].LHS] = false;
}
do {
changes = false;
for(size_t i = 0; i < rules.size(); i++) {
p = rules[i];
if(!derives_lambda[p.LHS]) {
if(p.RHS.size() == 0 || p.RHS[0] == Grammar::lambda) {
changes = derives_lambda[p.LHS] = true;
continue;
}
/* does each part of RHS derive lambda ? */
rhs_derives_lambda = derives_lambda[string(p.RHS[0])];
for(size_t j = 1; j < p.RHS.size(); j++) {
rhs_derives_lambda &= derives_lambda[p.RHS[j]];
}
if(rhs_derives_lambda) {
changes = true;
derives_lambda[p.LHS] = true;
}
}
}
} while(changes);
return derives_lambda;
}
void Grammar::fill_first_set() {
string A; // nonterminal
string a; // terminal
Production p;
bool changes;
mark_lambda();
first_set.clear();
for(size_t i = 0; i < rules.size(); i++) {
A = rules[i].LHS;
if(derives_lambda[A])
first_set[A].insert(Grammar::lambda);
}
for(size_t i = 0; i < rules.size(); i++) {
for(size_t j = 0; j < rules[i].RHS.size(); j++) {
a = rules[i].RHS[j];
if(!isNonterminal(a)) {
if(a != Grammar::lambda)
first_set[a].insert(a);
if(j == 0) { // A -> aXX
first_set[rules[i].LHS].insert(a);
}
}
}
}
do {
changes = false;
for(size_t i = 0; i < rules.size(); i++) {
p = rules[i];
set<string> rfirst = compute_first(p.RHS);
size_t oldsize = first_set[p.LHS].size();
first_set[p.LHS].insert(rfirst.begin(), rfirst.end());
size_t newsize = first_set[p.LHS].size();
if(oldsize != newsize)
changes = true;
}
} while(changes);
}
void Grammar::fill_follow_set() {
string A, B; // nonterminal
Production p;
bool changes;
for(size_t i = 0; i < rules.size(); i++) {
A = rules[i].LHS;
follow_set[A].clear();
}
follow_set[start_symbol].insert(Grammar::lambda);
do {
changes = false;
for(size_t i = 0; i < rules.size(); i++) {
/* A -> a B b
* I.e. for each production and each occurrence
* of a nonterminal in its right-hand side.
*/
p = rules[i];
A = p.LHS;
for(size_t j = 0; j < p.RHS.size(); j++) {
B = p.RHS[j];
if(isNonterminal(B)) {
vector<string> beta(p.RHS.begin() + j + 1, p.RHS.end());
set<string> rfirst = compute_first(beta);
size_t oldsize = follow_set[B].size();
if(rfirst.find(Grammar::lambda) == rfirst.end()) {
follow_set[B].insert(rfirst.begin(), rfirst.end());
} else {
rfirst.erase(Grammar::lambda);
follow_set[B].insert(rfirst.begin(), rfirst.end());
rfirst = follow_set[A];
follow_set[B].insert(rfirst.begin(), rfirst.end());
}
size_t newsize = follow_set[B].size();
if(oldsize != newsize)
changes = true;
}
}
}
} while(changes);
}
void Grammar::lldriver(queue<string> tokens) {
stack<string> stk;
string X;
string a;
Production p;
/* Push the Start Symbol onto an empty stack */
stk.push(start_symbol);
while(!stk.empty() && !tokens.empty()) {
X = stk.top();
a = tokens.front();
// cout << X << " " << a << endl;
if(isNonterminal(X) && lltable[X].find(a) != lltable[X].end()) {
p = lltable[X][a];
stk.pop();
for(int i = p.RHS.size() - 1; i >= 0; i--) {
if(p.RHS[i] == Grammar::lambda)
continue;
stk.push(p.RHS[i]);
}
} else if(X == a) {
stk.pop();
tokens.pop();
} else if(lltable[X].find(Grammar::lambda) != lltable[X].end()) {
stk.pop();
} else {
/* Process syntax error. */
puts("Bad!");
return;
}
}
while(!stk.empty()) {
X = stk.top();
if(lltable[X].find(Grammar::lambda) != lltable[X].end())
stk.pop();
else
break;
}
if(tokens.size() == 0 && stk.size() == 0)
puts("Good");
else
puts("Bad!");
return;
}
/* ------------------------
Grammar LR method
-------------------------- */
void Grammar::build_action() {
ConfigurationSet s;
Production P;
int dotPos;
set< pair<Production, ConfigurationSet::State> >::iterator it;
for(size_t i = 0; i < LRstates.size(); i++) {
s = LRstates[i];
int reduce = 0, rule = 0, accept = 1;
for(it = s.configs.begin(); it != s.configs.end(); it++) {
P = it->first, dotPos = it->second.dot;
if(dotPos == P.RHS.size())
reduce++, rule = P.label;
accept &= P.LHS == Grammar::start_symbol;
}
if(accept == 1)
action_table[i] = 0;
else if(reduce == 1)
action_table[i] = -1;
else
action_table[i] = 1;
}
#ifdef DEBUG
printf("State |");
for(size_t i = 0; i < LRstates.size(); i++)
printf("%5d|", i);
puts("");
printf("Action|");
for(size_t i = 0; i < action_table.size(); i++) {
printf("%5d|", action_table[i]);
}
puts("");
#endif
}
void Grammar::build_CFSM() {
set<ConfigurationSet> S;
queue<ConfigurationSet> Q;
ConfigurationSet s0, sb;
int label = 0;
ConfigurationSet::State state;
state.dot = 0;
state.lookahead = vector<string>();
state.lookahead.push_back(Grammar::lambda);
for(size_t i = 0; i < rules.size(); i++) {
if(rules[i].LHS == this->start_symbol) {
s0.configs.insert(make_pair(rules[i], state));
}
}
s0 = ConfigurationSet::closure0(s0, *this);
s0.label = label++;
S.insert(s0);
Q.push(s0);
buildSymbols();
/* hw need */
map<int, vector< pair<int, string> > > hwPrint;
/* hw need */
while(!Q.empty()) {
s0 = Q.front(), Q.pop();
LRstates.push_back(s0);
for(set<string>::iterator it = symbols.begin();
it != symbols.end(); it++) {
sb = ConfigurationSet::go_to0(s0, *it, *this);
if(sb.configs.size() > 0) {
if(S.find(sb) == S.end()) {
sb.label = label++;
S.insert(sb);
Q.push(sb);
}
go_to_table[s0.label][*it] = (* S.find(sb)).label;
/* hw need */
hwPrint[(* S.find(sb)).label].push_back(make_pair(s0.label, *it));
}
}
}
// build_action();
#ifdef DEBUG
printf("Total State: %d\n", label);
for(int i = 0; i < label; i++) {
if(hwPrint[i].size() > 0) {
printf("State %d from", i);
for(vector< pair<int, string> >::iterator it = hwPrint[i].begin();
it != hwPrint[i].end(); it++) {
printf("%cState %d(%s)", it == hwPrint[i].begin() ? ' ' : ',', it->first, it->second.c_str());
}
puts("");
} else {
printf("State %d\n", i);
}
LRstates[i].print(*this);
puts("");
}
#endif
}
int Grammar::slr1driver(queue<string> tokens) {
stack<int> stateStk;
stack<string> tokenStk;
int state;
string X;
stateStk.push(0); /* push start state */
while(!tokens.empty()) {
state = stateStk.top();
X = tokens.front();
#ifdef DEBUG
puts("");
printf("state %d front %s\n", state, X.c_str());
LRstates[state].print(*this);
for (std::stack<int> dump = stateStk; !dump.empty(); dump.pop())
std::cout << "state stack "<< dump.top() << '\n';
for (std::stack<string> dump = tokenStk; !dump.empty(); dump.pop())
std::cout << "token stack "<< dump.top() << '\n';
#endif
int reduce = 0, shift = 0;
Production P;
for(set< pair<Production, ConfigurationSet::State> >::iterator it = LRstates[state].configs.begin();
it != LRstates[state].configs.end(); it++) {
Production q = it->first;
ConfigurationSet::State s = it->second;
if(follow_set[q.LHS].find(X) != follow_set[q.LHS].end() &&
(s.dot == q.RHS.size() || q.RHS[0] == Grammar::lambda)) {
reduce++;
P = q;
}
}
if(go_to_table[state].find(X) != go_to_table[state].end())
shift++;
if(reduce + shift >= 2)
assert(false); // grammar can't use simple LR.
if(reduce + shift == 0)
return 0;
if(reduce == 1) { // Reduce
for(size_t i = 0; i < P.RHS.size(); i++)
tokenStk.pop(), stateStk.pop();
tokenStk.push(P.LHS);
state = stateStk.top();
if(go_to_table[state].find(P.LHS) == go_to_table[state].end()) {
return 0;
}
state = go_to_table[state][P.LHS];
stateStk.push(state);
} else { // shift
state = go_to_table[state][X];
stateStk.push(state);
tokenStk.push(X);
tokens.pop();
}
}
while(!stateStk.empty()) {
state = stateStk.top();
X = Grammar::lambda;
#ifdef DEBUG
puts("");
printf("state %d front %s\n", state, X.c_str());
LRstates[state].print(*this);
for (std::stack<int> dump = stateStk; !dump.empty(); dump.pop())
std::cout << "state stack "<< dump.top() << '\n';
for (std::stack<string> dump = tokenStk; !dump.empty(); dump.pop())
std::cout << "token stack "<< dump.top() << '\n';
#endif
int reduce = 0, shift = 0;
Production P;
for(set< pair<Production, ConfigurationSet::State> >::iterator it = LRstates[state].configs.begin();
it != LRstates[state].configs.end(); it++) {
Production q = it->first;
ConfigurationSet::State s = it->second;
if(follow_set[q.LHS].find(X) != follow_set[q.LHS].end() &&
(s.dot == q.RHS.size() || q.RHS[0] == Grammar::lambda)) {
reduce++;
P = q;
}
}
if(go_to_table[state].find(X) != go_to_table[state].end())
shift++;
if(reduce + shift >= 2)
assert(false); // grammar can't use simple LR.
if(reduce + shift == 0)
return 0;
if(reduce == 1) { // Reduce
for(size_t i = 0; i < P.RHS.size(); i++)
tokenStk.pop(), stateStk.pop();
tokenStk.push(P.LHS);
state = stateStk.top();
if(go_to_table[state].find(P.LHS) == go_to_table[state].end()) {
if(P.LHS == Grammar::start_symbol)
return 1;
return 0;
}
state = go_to_table[state][P.LHS];
stateStk.push(state);
} else { // shift
state = go_to_table[state][X];
stateStk.push(state);
tokenStk.push(X);
tokens.pop();
}
}
return 0;
}
void parsingProduction(string r, Grammar &g) {
static int production_label = 0;
stringstream sin(r);
string lhs, foo;
vector<string> tokens;
sin >> lhs >> foo;
while(sin >> foo)
tokens.push_back(foo);
Production p(lhs, tokens);
p.label = ++production_label;
g.rules.push_back(p);
}
bool isNumber(string str) {
for(int i = 0; i < str.length(); i++) {
if(!isdigit(str[i]))
return false;
}
return true;
}
int scanTokens(char s[], queue<string>& tokens, vector<string>& val) {
string keyword[18] = {"AND", "THEN", "GO", "KEEP",
"RIGHT", "LEFT", "FIRST", "SECOND", "THIRD",
"AT", "RECORD", "TIME", "TO", "KMH", "CHANGE",
"AVERAGE", "SPEED", "CAS"};
for(int i = 0; s[i]; i++) {
if(s[i] == '"') {
// s-word can't empty, and after the opening speech marks no more space.
if(s[i + 1] == '"' || isspace(s[i + 1]))
return 0;
i++;
while(s[i] != '"') {
if(isupper(s[i])) {}
else if(isspace(s[i])) {s[i] = '_';}
else if(s[i] == '.') {
if(isspace(s[i - 1]) || s[i - 1] == '_') {
return 0;
}
} else {
return 0;
}
i++;
}
if(s[i] == '\0' || isspace(s[i - 1]) || s[i - 1] == '_')
return 0;
}
}
stringstream sin(s);
string token;
while(sin >> token) {
int f = 0;
for(int i = 0; i < 18; i++) {
if(token == keyword[i])
tokens.push(token), val.push_back(token), f = 1;
}
if(f) continue;
if(token[0] == '"')
tokens.push("SIGNWORDS"), val.push_back(token), f = 1;
if(f) continue;
if(isNumber(token))
tokens.push("NNN"), val.push_back(token), f = 1;
if(f) continue;
return 0;
}
return 1;
}
int main() {
// freopen("in.txt", "r+t", stdin);
// freopen("out.txt", "w+t", stdout);
Grammar g;
parsingProduction("<instruction> -> <navigational>", g);
parsingProduction("<instruction> -> <time-keeping>", g);
parsingProduction("<instruction> -> <navigational> AND <time-keeping>", g);
parsingProduction("<navigational> -> <directional>", g);
parsingProduction("<navigational> -> <navigational> AND THEN <directional>", g);
parsingProduction("<directional> -> <how> <direction>", g);
parsingProduction("<directional> -> <how> <direction> <where>", g);
parsingProduction("<how> -> GO", g);
parsingProduction("<how> -> GO <when>", g);
parsingProduction("<how> -> KEEP", g);
parsingProduction("<direction> -> RIGHT", g);
parsingProduction("<direction> -> LEFT", g);
parsingProduction("<when> -> FIRST", g);
parsingProduction("<when> -> SECOND", g);
parsingProduction("<when> -> THIRD", g);
parsingProduction("<where> -> AT <sign>", g);
parsingProduction("<sign> -> SIGNWORDS", g);
parsingProduction("<time-keeping> -> <record>", g);
parsingProduction("<time-keeping> -> <change>", g);
parsingProduction("<record> -> RECORD TIME", g);
parsingProduction("<change> -> <cas> TO NNN KMH", g);
parsingProduction("<cas> -> CHANGE AVERAGE SPEED", g);
parsingProduction("<cas> -> CAS", g);
g.start_symbol = "<instruction>";
g.fill_first_set();
g.fill_follow_set();
g.build_CFSM();
char line[1024];
int cases = 0;
while(gets(line)) {
if(!strcmp(line, "#"))
break;
queue<string> tokens;
vector<string> val;
int f = scanTokens(line, tokens, val);
printf("%3d.", ++cases);
if(!f) {
puts(" Trap!");
continue;
}
f = g.slr1driver(tokens);
if(!f) {
puts(" Trap!");
continue;
}
for(int i = 0; i < val.size(); i++) {
if(val[i][0] == '"')
for(int j = 0; j < val[i].length(); j++)
if(val[i][j] == '_')
val[i][j] = ' ';
printf(" %s", val[i].c_str());
}
puts("");
}
return 0;
}
Read More +

UVa 345 - It's Ir-Resist-Able

Problem

A common component in electronic circuits is the resistor. Each resistor has two terminals, and when current flows through a resistor, some of it is converted to heat, thus ``resisting”; the flow of the current. The extent to which it does this is indicated by a single positive numeric value, cleverly called the resistance of the resistor. By the way, the units of resistance are Ohms. Here’s what a single resistor looks like in a diagram of an electronic circuit:

When two resistors are connected in series, as shown below, then their equivalent resistance is just the sum of the resistances of the individual resistors. For example, if the two resistors below had resistances of 100 and 200 Ohms, respectively, then the combined resistance (from point A to point B) would be 300 Ohms. Of course, combining three or more resistors in series would yield a resistance equal to sum of all the individual resistances.

Resistors may also be connected in parallel, like this:

If these two resistors had resistances of 100 and 150 Ohms, then the parallel combination would yield an equivalent resistance between points A and B of

displaymath61

Connecting three resistors in parallel uses the same rule, so a 100 Ohm, 150 Ohm, and 300 Ohm resistor in parallel would yield a combined resistance of just 50 Ohms: that is,

displaymath63

In this problem you’re provided one or more descriptions of resistors and their interconnections. Each possible interconnection point (the terminals of a resistor) is identified by a unique positive integer, its label. And each resistor is specified by giving its two interconnection point labels and its resistance (as a real number).

For example, the input

1 2 100

would tell us that a 100 Ohm resistor was connected between points 1 and 2. A pair of resistors connected in series might be specified like this:

1 2 100
2 3 200

Here we’ve got our 100 Ohm resistor connected at points 1 and 2, and another 200 Ohm resistor connected to points 2 and 3. Two resistors in parallel would be similarly specified:

1 2 100
1 2 150

Once you know how the resistors are interconnected, and the resistance of each resistor, it’s possible to determine the equivalent resistance between any two points using the simple rules given above. In some cases, that is. Some interconnections of resistors can’t be solved using this approach: you won’t encounter any of these in this problem, however.

Notes

  • Be aware that there may be input test cases with some resistors that don’t contribute to the overall resistance between the indicated points. For example, in the last case shown in the Sample Input section below, the resistor between points 1 and 2 is unused. There must be some flow through a resistor if it is to contribute to the overall resistance.
  • No resistor will have its ends connected together. That is, the labels associated with the ends of a resistor will always be distinct.

Input

There will be one or more cases to consider. Each will begin with a line containing three integers N, A, and B. A and B indicate the labels of points between which you are to determine the equivalent resistance. N is the number of individual resistors, and will be no larger than 30. N, A and B will all be zero in the line following the last case. Following each N A B line will be N lines, each specifying the labels of the points where a resistor is connected, and the resistance of that resistor, given as a real number.

Output

For each input case, display a line that includes the case number (they are numbered sequentially starting with 1) and the equivalent resistance, accurate to two decimal places.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
2 1 3
1 2 100
2 3 200
2 1 2
1 2 100
1 2 150
6 1 6
1 2 500
1 3 15
3 4 40
3 5 100
4 6 60
5 6 50
0 0 0

Sample Output

1
2
3
Case 1: 300.00 Ohms
Case 2: 60.00 Ohms
Case 3: 75.00 Ohms

Solution

題目描述:

給定指定的兩個端點 A B,接著會有 N 個電阻,每個電阻值位於端點 X Y 之間。
求 A B 之間的等效電阻,特別注意到端點編號是任意整數,並且有可能兩個端點相同 (A = B),也有可能會有無會流經的電路區域。

題目解法:

我們假設每個端點的電動勢 (Volt),使用克希荷夫電路定律(Kirchhoff Circuit Laws)中的 電流定律 ,得到下列公式。

對於每一個端點而言,入電流總量等於出電流總量:

$\sum_{j = 1}^{n} \frac{V_{j} - V_{i}}{R_{i, j}} = 0$

但是題目給定的起點和終點並不會在其中,因此假設起點 V[A] = INF,終點 V[B] = 0,接著算出其他所有點的電動勢。共有 n - 2 條方程式,n - 2 個變數,使用高斯消去求解。

  • 必須預處理與起點、終點之間的電流關係。
  • 特別注意到起點和終點相同,直接輸出等效電阻 0。
  • 端點編號離散化集中處理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <math.h>
#include <map>
#include <iostream>
using namespace std;
// learn: http://blog.csdn.net/jiangshibiao/article/details/28661223
#define MAXN 105
#define INF 1e+6
#define eps 1e-9
double R[MAXN][MAXN] = {}, V[MAXN] = {}; // R: resist, V: voltage
double f[MAXN][MAXN] = {}; // function need solved;
int main() {
int N, A, B;
int x, y, l;
int cases = 0;
double w;
char s1[105], s2[105];
while(scanf("%d %d %d", &N, &A, &B) == 3) {
if(N == 0)
break;
map<int, int> label;
l = label[A];
if(l == 0) label[A] = label.size();
A = label[A];
l = label[B];
if(l == 0) label[B] = label.size();
B = label[B];
memset(R, 0, sizeof(R));
memset(V, 0, sizeof(V));
memset(f, 0, sizeof(f));
vector<double> g[MAXN][MAXN];
for(int i = 0; i < N; i++) {
scanf("%d %d %lf", &x, &y, &w);
l = label[x];
if(l == 0) label[x] = label.size();
x = label[x];
l = label[y];
if(l == 0) label[y] = label.size();
y = label[y];
g[x][y].push_back(w);
g[y][x].push_back(w);
}
N = label.size();
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= N; j++) {
if(g[i][j].size()) {
double r = 0;
for(int k = 0; k < g[i][j].size(); k++) {
r += 1.0 / g[i][j][k];
}
R[i][j] = 1.0 / r;
}
}
}
V[A] = INF, V[B] = 0;
for(int i = 1; i <= N; i++) {
if(i == A) continue;
if(i == B) continue;
if(R[i][A] > 0)
f[i][i] -= 1.0 / R[i][A], f[i][N + 1] -= V[A] / R[i][A];
if(R[i][B] > 0)
f[i][i] -= 1.0 / R[i][B], f[i][N + 1] -= V[B] / R[i][B];
for(int j = 1; j <= N; j++) {
if(R[i][j] > 0 && i != j && j != A && j != B)
f[i][j] = 1.0 / R[i][j], f[i][i] -= 1.0 / R[i][j];
}
}
// Gaussian Elimination
for(int i = 1; i <= N; i++) {
int k = i;
for(int j = i + 1; j <= N; j++)
if(f[j][i] > 0)
k = j;
if(fabs(f[k][i]) < eps)
continue;
for(int j = 1; j <= N + 1; j++)
swap(f[i][j], f[k][j]);
for(int j = 1; j <= N; j++) {
if(i == j) continue;
for(int k = N + 1; k >= i; k--)
f[j][k] = f[j][k] - f[j][i] / f[i][i] * f[i][k];
}
}
for(int i = 1; i <= N; i++) {
if(i == A) continue;
if(i == B) continue;
if(fabs(f[i][i]) > eps)
V[i] = f[i][N + 1] / f[i][i];
}
double IB = 0;
for(int i = 1; i <= N; i++)
if(R[i][B] > 0)
IB += V[i] / R[i][B];
if(fabs(IB) < eps)
printf("Case %d: %.2lf Ohms\n", ++cases, 0);
else
printf("Case %d: %.2lf Ohms\n", ++cases, (V[A] - V[B]) / IB);
}
return 0;
}
Read More +

UVa 313 - Intervals

Problem

In the ceiling in the basement of a newly open developers building a light source has been installed. Unfortunately, the material used to cover the floor is very sensitive to light. It turned out that its expected life time is decreasing dramatically. To avoid this, authorities have decided to protect light sensitive areas from strong light by covering them. The solution was not very easy because, as it is common, in the basement there are different pipelines under the ceiling and the authorities want to install the covers just on those parts of the floor that are not shielded from the light by pipes. To cope with the situation, the first decision was to simplify the real situation and, instead of solving the problem in 3D space, to construct a 2D model first.

Within this model, the x-axis has been aligned with the level of the floor. The light is considered to be a point light source with integer co-ordinates tex2html_wrap_inline36 . The pipes are represented by circles. The center of the circle i has the integer co-ordinates tex2html_wrap_inline40 and an integer radius tex2html_wrap_inline42 . As pipes are made from solid material, circles cannot overlap. Pipes cannot reflect the light and the light cannot go through the pipes. You have to write a program which will determine the non-overlapping intervals on the x-axis where there is, due to the pipes, no light from the light source.

Input

The input file consists of blocks of lines, each of which except the last describes one situation in the basement. The first line of each block contains a positive integer number N < 500 expressing the number of pipes. The second line of the block contains two integers tex2html_wrap_inline48 and tex2html_wrap_inline50 separated by one space. Each of the next N lines of the block contains integers tex2html_wrap_inline54 , tex2html_wrap_inline56 and tex2html_wrap_inline42 , where tex2html_wrap_inline60 . Integers in individual lines are separated by one space. The last block consists of one line containing n = 0.

Output

The output file consists of blocks of lines, corresponding to the blocks in the file (except the last one). One empty line must be put after each block in the output file. Each of the individual lines of the blocks in the output file will contain two real numbers, the endpoints of the interval where there is no light from the given point light source. The reals are exact to two decimal places and separated by one space. The intervals are sorted according to increasing x-coordinate.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
6
300 450
70 50 30
120 20 20
270 40 10
250 85 20
220 30 30
380 100 100
1
300 300
300 150 90
1
300 300
390 150 90
0

Sample Output

1
2
3
4
5
6
7
0.72 78.86
88.50 133.94
181.04 549.93
75.00 525.00
300.00 862.50

Solution

題目描述:

現在天花板上面有一盞燈,然後下方有數個圓,請問陰影部分的區間由小至大輸出分別為何。
假設不會有圓的高度大於燈的位置,而陰影呈現在 x 軸上。

題目解法:

求圓 (cx, cy, r) 外一點的切線,由於點 (a, b) 在圓外,通常此點切於圓的線會有兩條。

假設該線斜率為 m,則通過的線為 y = m * (x - a) + b

藉由點線距公式 |m * (cx - a) - cy + b |/sqrt(m*m + 1) = r,求得 m 之後得到兩條切線,往後求交 x 軸的位置即可。(特別考慮 m 不存在的情況)

最後使用掃描線算法來算聯集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <math.h>
using namespace std;
int main() {
int N;
double bx, by, cx, cy, cr;
while (scanf("%d", &N) == 1 && N) {
scanf("%lf %lf", &bx, &by);
vector< pair<double, double> > interval;
for (int i = 0; i < N; i++) {
scanf("%lf %lf %lf", &cx, &cy, &cr);
double a, b, c;
a = (cx - bx) * (cx - bx) - cr * cr;
b = 2 * (cx - bx) * (by - cy);
c = (by - cy) * (by - cy) - cr * cr;
if (b * b - 4 * a * c > 0) {
#define eps 1e-6
if (fabs(a) > eps) {
double m1 = (-b + sqrt(b * b - 4 * a * c))/(2 * a);
double m2 = (-b - sqrt(b * b - 4 * a * c))/(2 * a);
double l, r;
c = by - m1 * bx;
l = -c / m1;
c = by - m2 * bx;
r = -c / m2;
if (l >= r)
swap(l, r);
interval.push_back(make_pair(l, r));
} else {
double m1 = -c / b;
double l, r;
c = by - m1 * bx;
l = -c / m1;
r = bx;
if (l >= r)
swap(l, r);
interval.push_back(make_pair(l, r));
}
}
}
sort(interval.begin(), interval.end());
double coverL, coverR;
coverL = interval[0].first;
coverR = interval[0].second;
for (int i = 0; i < interval.size(); i++) {
if (interval[i].first <= coverR) {
coverR = max(coverR, interval[i].second);
} else {
printf("%.2lf %.2lf\n", coverL, coverR);
coverL = interval[i].first;
coverR = interval[i].second;
}
}
printf("%.2lf %.2lf\n", coverL, coverR);
puts("");
}
return 0;
}
Read More +

UVa 10118 - Free Candies

The Problem

Little Bob is playing a game. He wants to win some candies in it - as many as possible.

There are 4 piles, each pile contains N candies. Bob is given a basket which can hold at most 5 candies. Each time, he puts a candy at the top of one pile into the basket, and if there’re two candies of the same color in it ,he can take both of them outside the basket and put them into his own pocket. When the basket is full and there are no two candies of the same color, the game ends. If the game is played perfectly, the game will end with no candies left in the piles.

For example, Bob may play this game like this (N=5):

Step1 Initial Piles Step2 Take one from pile #2
Piles Basket Pocket Piles Basket Pocket

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

nothing     nothing     

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

2     nothing

Step3 Take one from pile #2 Step4 Take one from pile #3
Piles Basket Pocket Piles Basket Pocket

1 3 4
1 6 7
2 3 3 3
4 9 8 6
8 7 2 1

2 5     nothing     

1 4
1 6 7
2 3 3 3
4 9 8 6
8 7 2 1

2 3 5     nothing

Step5 Take one from pile #2 Step6 put two candies into his pocket
Piles Basket Pocket Piles Basket Pocket

1 4
1 6 7
2 3 3
4 9 8 6
8 7 2 1

2 3 3 5     nothing     

1 4
1 6 7
2 3 3
4 9 8 6
8 7 2 1

2 5     a pair of 3

Note that different numbers indicate different colors, there are 20 kinds of colors numbered 1..20.

‘Seems so hard…’Bob got very much puzzled. How many pairs of candies could he take home at most?

The Input

The input will contain no more than 10 test cases. Each test case begins with a line containing a single integer n(1<=n<=40) representing the height of the piles. In the following n lines, each line contains four integers xi1,xi2,xi3,xi4 (in the range 1..20). Each integer indicates the color of the corresponding candy. The test case containing n=0 will terminate the input, you should not give an answer to this case.

The Output

Output the number of pairs of candies that the cleverest little child can take home. Print your answer in a single line for each test case.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
5
1 2 3 4
1 5 6 7
2 3 3 3
4 9 8 6
8 7 2 1
1
1 2 3 4
3
1 2 3 4
5 6 7 8
1 2 3 4
0

Sample Output

1
2
3
8
0
3

Solution

題目描述:

現在盤面上共有 4 堆,每一堆呈現 stack 的方式,並且每一堆都會有 n 個糖果,接下來每一步將會把每一堆的 top 糖果放入籃子中,假使籃子中有相同編號的糖果,則會將這兩個相同編號的糖果收入口袋。請問到籃子滿 5 個糖果之前,最多有多少對的糖果可以帶回家。

題目解法:

將搜索狀態進行標記,之後走訪遇到相同狀態直接退回。這個問題在相同狀態下的結果必然相同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <algorithm>
#include <iostream>
using namespace std;
#define MAXN 45
int N, pile[4][MAXN];
int used[MAXN][MAXN][MAXN][MAXN] = {}, testcase = 0;
int dp[MAXN][MAXN][MAXN][MAXN];
int dfs(int p1, int p2, int p3, int p4, int state) {
if(__builtin_popcount(state) == 5)
return 0;
if(used[p1][p2][p3][p4] == testcase)
return dp[p1][p2][p3][p4];
used[p1][p2][p3][p4] = testcase;
int &ret = dp[p1][p2][p3][p4];
int t, v;
ret = 0;
if(p1 < N) {
t = pile[0][p1];
v = (state>>t)&1;
ret = max(ret, v + dfs(p1+1, p2, p3, p4, state^(1<<t)));
}
if(p2 < N) {
t = pile[1][p2];
v = (state>>t)&1;
ret = max(ret, v + dfs(p1, p2+1, p3, p4, state^(1<<t)));
}
if(p3 < N) {
t = pile[2][p3];
v = (state>>t)&1;
ret = max(ret, v + dfs(p1, p2, p3+1, p4, state^(1<<t)));
}
if(p4 < N) {
t = pile[3][p4];
v = (state>>t)&1;
ret = max(ret, v + dfs(p1, p2, p3, p4+1, state^(1<<t)));
}
return ret;
}
int main() {
while(scanf("%d", &N) == 1 && N) {
for(int i = 0; i < N; i++)
for(int j = 0; j < 4; j++)
scanf("%d", &pile[j][i]);
testcase++;
int ret = dfs(0, 0, 0, 0, 0);
printf("%d\n", ret);
}
return 0;
}
Read More +

作業系統 筆記 (2)

精簡

Page-replacement algorithm

  • FIFO Algorithm
    最先載入的 Page (即:Loading Time最小者),優先視為 Victim Page。
  • Optimal Algorithm(OPT)
    以 “將來長期不會使用的 Page Page” 視為Victim Page。
  • Least Recently Used Algorithm (LRU)
    以 “最近不常使用的 Page Page” 視為Victim Page。
    • 緣由:LRU製作成本過高
    • 作法:
      • Second econd Chance ( 二次機會法則 )
      • Enhance nhance Second Chance ( 加強式二次機會法則 )
    • 有可能退化成 FIFO FIFO,會遇到 Belady 異常情況
  • Second Chance (二次機會法則)
    以 FIFO 法則為基礎,搭配 Reference Bit 使用,參照過兩次以上的 page 將不會被置換出去,除非全部都是參照兩次以上,將會退化成 FIFO。
  • Enhance Second Chance (加強式二次機會法則)
    使用(Reference Bit Bit, Modification Bit Bit) 配對值作為挑選 Victim Page 的依據。對於沒有沒修改的 page 優先被置換,減少置換的成本。
  • Belady’s anomaly 當 Process 分配到較多的 Frame 數量,有時其 Page Fault Ratio 卻不降反升。
Rank Algorithm Suffer from Belady’s anomaly
1 Optimal no
2 LRU no
3 Second-chance yes
4 FIFO yes

Thrashing(振盪)

當 CPU 效能低時,系統會想引入更多的 process 讓 CPU 盡可能地工作。但當存有太多 process 時,大部分的工作將會花費在 page fault 造成的 Page Replacement,致使 CPU 效率下降,最後造成 CPU 的效能越來越低。

解決方法

  • [方法 1]
    降低 Multiprogramming Degree。
  • [方法 2]
    利用 Page Fault Frequency (Ratio) 控制來防止 Thrashing。
  • [方法 3]
    利用 Working Set Model “預估 ” 各 Process 在不同執行時期所需的頁框數,並依此提供足夠的頁框數,以防止 Thrashing。
    • 作法
      OS 設定一個Working Set Window (工作集視窗;Δ) 大小,以Δ 次記憶體存取中,所存取到的不同Page之集合,此一集合稱為 Working Set 。而Working Set中的Process個數,稱為 Working Set Size ( 工作集大小; WSS) 。

Page

  • Page Size 愈小
    • 缺點
      • Page fault ratio愈高
      • Page Table Size愈大
      • I/O Time (執行整個Process的I/O Time) 愈大
    • 優點
      • 內部碎裂愈小
      • Total I/O Time (單一Page的Transfer Time) 愈小
      • Locality愈集中

Fragmentation

分成外部和內部碎裂 External & Internal Fragmentation

Deadlock(死結)

  • 成因
    1. mutual exclusion 資源互斥
      一個資源只能分配給一個 process,不能同時分配給多個 process 同時使用。
    2. hold-and-wait 擁有並等待
      擁有部分請求的資源,同時等待別的 process 所擁有資源
    3. no preemption 不可搶先
      不可搶奪別的 process 已經擁有的資源
    4. circular wait 循環等待
      存有循環等待的情況

解決方法

  • Dead Lock Prevention
    不會存有死結成因四條中的任何一條。
  • Dead Lock Avoidance
    對運行的情況做模擬,找一個簡單的算法查看是否有解死結,但這算法可能會導致可解的情況,歸屬在不可解的情況。
    • Use a. to get: $\sum Need + \sum Allocation < m + n$
    • Use c. to get: $\sum Need_{i} + m < m + n$
    • Rewrite to get: $\sum Need_{i} < n$
  • Dead Lock Detection & Recovery
    Recovery 成本太高

小問題

  • Propose two approaches to protect files in a file system.
    檔案系統如何保護檔案?請提供兩種方式。

    對檔案做加密動作,或者將檔案藏起-不可讀取。

  • The system will enter deadlock if you cannot find a safe sequence for
    it, YES or NO? Please draw a diagram to explain your answer.
    如果找不到一個安全序列,是否就代表系統進入死結?

    不會,因為找尋安全序列的方式通常是精心設計的通則,也就是說每個程序要求資源的方式都是可預期的運作,但實際上並不是如此,而且順序和運作都是各自獨立且不可預期,有可能途中就會釋放資源。

  • spinlock mutex semaphore 三者的區分?

    spinlock(自旋鎖)是一種佔有 CPU 效能的一種 busy waiting,而 mutex 和 semaphore 是一種根據一個資料物件來達到互斥的效果。

    就以 spinlock 來說,比較適合鎖較短的指令。相反地,mutex 和 semaphore 用於鎖住區域 (critical section) 的指令代碼。

    回過頭看 mutex 和 semaphore,mutex 只能限制單一程序進入 critical section,而 semaphore 可以自訂有多少程序可以進度 critical section,就以 binary semaphore 來說,其功能效應等同於 mutex。

Read More +

大學生跳樓

關於

跳樓這件事情越來越不稀奇,不只有在台灣,在中國大陸那邊也是頻頻出現的事件。

近年来,有关大学生以及研究生,博士生自杀的新闻经常见诸报端,以至于让人们产生审自杀疲劳。当下除了清华北大的硕士博士跳楼自杀还能称之为新闻外,一些名不见经传的普通学校里的学生自杀,已经不能算新闻。

而最引人关注和热议的,无疑是2009年研究生杨元元的自杀身亡。她的信念是“知识可以改变命运”,可是和蔡某某一样,她奋斗多年学到了许多知识,名牌大学也毕业了,研究生也考上了,到了可以改变人生的时候了,但却没有任何起色,但却找不到理想的工作,不仅养不好家人与自己、解决不了面对的种种人生难题,反而越来越糟──“都说知识改变命运,为什么我学了那么多知识,也没见有什么改变?”此一问的背后是:活着又有何益呢?自杀成了她可悲的选择。
大学生自杀频现,教育之责何在?

《我奋斗了18年才和你坐在一起喝咖啡》

統計

自殺不成的就沒有列,還有部分出現的新聞,但是網上缺資料。

  • 2012年11月26日
    東吳大一女墜樓 發票留言:對不起
  • 2013年02月20日
    台大大四女學生 校園內跳樓輕生
  • 2013年12月08日
    台灣大學學生跳樓身亡「媽是否不要我」
  • 2014年04月08日
    中央大學博士生上吊自殺
  • 2014年05月20日
    中興大學 30 歲男碩士生校內 12 樓墜落身亡
  • 2014年06月09日
    政治大學法律系延畢生當晚回家跳樓

求資料

Read More +

UVa 12598 - Starting School

Problem

The first day of school is a very memorable day to everyone. Po is starting school from today and Po is very excited. As this is Po’s first day at school, no one is assigned roll number yet. So all the students form a line in the school field and they are being assigned roll number one by one. The teacher is a bit crazy. Instead of assigning roll number from 1, she starts assigning them one by one in a random fashion. Po watches this madness for the first K students and then steps up. Po says Po can assign them very easily for the rest of the students. The idea is very simple. Roll number should be unique and a student should get the smallest roll number that has not been assigned yet to any of the students. For example if K = 4, total number of students are 10 and the first K students’ roll numbers are 1, 3, 5, 10 then the next 6 roll numbers should be 2, 4, 6, 7, 8 and 9.

開學第一天是值得紀念的,Po 從今天開始在這所學校上課,他相當地興奮。Po 到達學校的第一天,沒有人被指派座號,因此所有的學生都在操場上等著被一個接著一個發送座號。老師有點喪心病狂,一開始從 1 號開始發送,但是他採用隨機發送,並沒有按著順序發。Po 看到前 K 位同學被這麼發送,Po 認為自己可以發送剩餘的學生編號,而發送方式相當簡單,將剩餘的最小座號發送給當前編號最小 (一開始規定學生編號為 1 - n) 的學生。

K = 4,一開始指派編號給 1 3 5 10 的學生座號,而剩餘座號就是發送順序為 2 4 6 7 8 9。

Though this is a very good idea, the teacher got mad at Po. So she starts asking the roll number for various students. As there are many students, Po is feeling helpless. Can you help Po?

Input

First line will contain an integer T (T <= 30), the number of test cases. Each case will start with three integers N (0 < N <= 109), K (0 < K <= 50,000 and K <= N) and Q (0 < Q <= 50,000). N is the total number of students, K is described earlier and Q is the number of queries of the crazy teacher. Next line will contain K distinct integers, the first K roll number assigned by the teacher. These values will be between 1 and 1000000000 (inclusive). Next will be Q integers, each indicating a position of students. These values will be between 1 and N (inclusive). (Large input output file, use faster I/O)

Output

For each case print one line “Case T:” where T is the case number. Then for each query print one line with the roll number of the student standing on the queried position. See sample I/O for clarity.

Sample Input

1
2
3
4
5
6
7
2
10 4 4
1 3 5 2
5 6 9 10
10 3 2
10 1 9
4 10

Output for Sample Input

1
2
3
4
5
6
7
8
Case 1:
4
6
9
10
Case 2:
2
8

Solution

題目解法:

將沒有分配到的連續區間壓縮,接著對於詢問二分搜索即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <algorithm>
using namespace std;
int A[65536], B[65536], C[65536], D[65536];
int main() {
int testcase, cases = 0, N, K, Q;
int x, l, r;
scanf("%d", &testcase);
while(testcase--) {
scanf("%d %d %d", &N, &K, &Q);
for(int i = 1; i <= K; i++)
scanf("%d", &A[i]), B[i] = A[i];
sort(B + 1, B + 1 + K);
B[0] = 0, B[K+1] = N + 1;
int M = 1;
C[0] = 0;
for(int i = 1; i <= K + 1; i++) {
l = B[i - 1] + 1, r = B[i] - 1;
if(l <= r) {
C[M] = C[M - 1] + r - l + 1;
D[M] = l;
M++;
}
}
printf("Case %d:\n", ++cases);
while(Q--) {
scanf("%d", &x);
if(x <= K)
printf("%d\n", A[x]);
else {
x -= K;
int pos = lower_bound(C, C + M, x) - C;
printf("%d\n", D[pos] + x - C[pos-1] - 1);
}
}
}
return 0;
}

加速 IO 的做法如下,優化輸入函數,以及反饋的二分搜索,但是排名還是沒有達到想要的目標。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <stdio.h>
#include <algorithm>
using namespace std;
int A[65536], B[65536], C[65536], D[65536];
inline int readchar() {
const int N = 1048576;
static char buf[N];
static char *p = buf, *end = buf;
if(p == end) {
if((end = buf + fread(buf, 1, N, stdin)) == buf) return EOF;
p = buf;
}
return *p++;
}
inline int ReadInt(int *x) {
static char c, neg;
while((c = readchar()) < '-') {if(c == EOF) return 0;}
neg = (c == '-') ? -1 : 1;
*x = (neg == 1) ? c-'0' : 0;
while((c = readchar()) >= '0')
*x = (*x << 3) + (*x << 1) + c-'0';
*x *= neg;
return 1;
}
int main() {
int testcase, cases = 0, N, K, Q;
int x, l, r;
ReadInt(&testcase);
while(testcase--) {
ReadInt(&N);
ReadInt(&K);
ReadInt(&Q);
int *p = A + 1, *q = B + 1;
for(int i = 1; i <= K; i++, p++, q++) {
ReadInt(p), *q = *p;
}
sort(B + 1, B + 1 + K);
B[0] = 0, B[K+1] = N + 1;
int M = 1;
C[0] = 0;
p = B, q = p+1;
for(int i = 1; i <= K + 1; i++, p = q++) {
l = *p + 1, r = *q - 1;
if(l <= r) {
C[M] = C[M - 1] + r - l + 1;
D[M] = l;
M++;
}
}
printf("Case %d:\n", ++cases);
int prevX = 0, prevP = 0, pos;
while(Q--) {
ReadInt(&x);
if(x <= K)
printf("%d\n", A[x]);
else {
x -= K;
if(x >= prevX)
pos = lower_bound(C + prevP, C + M, x) - C;
else
pos = lower_bound(C, C + prevP, x) - C;
printf("%d\n", D[pos] + x - C[pos-1] - 1);
prevX = x, prevP = pos;
}
}
}
return 0;
}
Read More +

UVa 11031 - Looking for a Subset

Problem

Given a set S = { a1, a2, a3, … , an }, you have to find a subset of S, P = { ax1, ax2, ax3, … , axm } such that ( x1 < x2 < … < xm ) and ( ax1< ax2< … < axm ). If there are several subsets possible then you should find the subset where x1 is minimum. If there is still a tie then check for the lowest x2 and so on.

Input

The input file contains several sets of inputs. The total number of test cases will be less than 25. The description of each set is given below:

Each case starts with two integers n (1 ≤ n ≤ 10000) and q (1 ≤ q ≤ 100), q is the number of queries. The next line contains n integers (seperated by a space) denoting a1, a2, a3, … , an respectively. And the next q lines, each contains an integer denoting m (1 ≤ m ≤ n). There is no number in the input file that contains more than 8 digits.

The input will be terminated by the case where n = q = 0. And this case should not be processed.

Output

For each case in the input, you should first print the case number starting from 1.
Then for each query first print the query number starting from 1. And for each m you have to find the result.
If there exists a subset as described above you should print the elements of the subset in a single line. The numbers should be seperated by a space.
Otherwise print ``Impossible’’ without the quotes.

See the sample input-output for more details. Output should be formatted like the sample output.

Sample Input

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

Output for Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
Set 1:
Subset 1:
Impossible
Subset 2:
1 2 3 6
Subset 3:
Impossible
Set 2:
Subset 1:
2 4 6
Subset 2:
Impossible

Solution

題目描述:

對於每次詢問 m,找到一個嚴格遞增的子序列,並且子序列長度等於 m 且字典順序最小。

題目解法:

基於每次字典順序最小,只能採用 greedy 的掃描方式,因此對於每次詢問必須到達 O(n),無法在 O(m) 的時間完成。

關於貪心的操作,建造反向的遞減序列,狀態為 從這個位置為子序列的頭最長的遞減序列長度為何。

為了在 O(n log n) 得到 LDS 表格,這裡使用一個 binary indexed tree 來完成操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <stdio.h>
#include <algorithm>
#include <map>
using namespace std;
#define maxN 10005
int A[maxN], LDS[maxN];
int BIT[maxN];
void modify(int i, int val, int L) {
while(i <= L) {
BIT[i] = max(BIT[i], val);
i += i&(-i);
}
}
int query(int i) {
int ret = 0;
while(i) {
ret = max(ret, BIT[i]);
i -= i&(-i);
}
return ret;
}
inline int readchar() {
const int N = 1048576;
static char buf[N];
static char *p = buf, *end = buf;
if(p == end) {
if((end = buf + fread(buf, 1, N, stdin)) == buf) return EOF;
p = buf;
}
return *p++;
}
inline int ReadInt(int *x) {
static char c, neg;
while((c = readchar()) < '-') {if(c == EOF) return 0;}
neg = (c == '-') ? -1 : 1;
*x = (neg == 1) ? c-'0' : 0;
while((c = readchar()) >= '0')
*x = (*x << 3) + (*x << 1) + c-'0';
*x *= neg;
return 1;
}
int main() {
int N, Q, M, u;
int cases = 0;
while(ReadInt(&N) && ReadInt(&Q) && N+Q) {
map<int, int> R;
for(int i = 0; i < N; i++) {
ReadInt(A+i);
R[A[i]] = 0;
}
for(int i = 1; i <= N; i++)
BIT[i] = 0;
int size = R.size();
for(map<int, int>::iterator it = R.begin();
it != R.end(); it++) {
it->second = size--;
}
/* reverse LDS with ending at i-th element */
int maxLDS = 0;
for(int i = N-1; i >= 0; i--) {
LDS[i] = query((u = R[A[i]]) - 1) + 1;
modify(u, LDS[i], R.size());
maxLDS = max(maxLDS, LDS[i]);
}
printf("Set %d:\n", ++cases);
for(int i = 1; i <= Q; i++) {
ReadInt(&M);
printf(" Subset %d:\n", i);
if(M > maxLDS) {
printf(" Impossible\n");
continue;
}
printf(" ");
int prevA = -0x3f3f3f3f;
for(int j = 0; j < N && M; j++) {
if(LDS[j] >= M && prevA < A[j]) {
printf(" %d", A[j]);
M--, prevA = A[j];
}
}
puts("");
}
}
return 0;
}
Read More +

當代消費文化與社會 (3)

作文本文:

看到今年作文的題目:人只有站著世界才屬於他,這使我突然想起一個中國的近代作家的墓誌銘:我死後請將我站著埋葬,因為我活著的時候一直都跪著。

這是一個生在新中國,長在紅旗下的作家,他直到臨死的時候才發出這樣的哀鳴,可見他還是人性未泯,知道跪著的屈辱和站著的不宜。的確,半個世紀以來,中國 人中並不缺少想站著活的人,但他們無一例外成為了“杯具”,我記得其中幾個人的名字:林紹,為了站著說出真理,她被子彈打爆了纖弱的頭顱,並且,他的親人 還要再花上5毛錢來購買奪取親人生命的那顆子彈。楊佳,為了站著討要一個說法,他同樣是被子彈打碎了心臟,唯一和林紹不同的是,他的親人不需要再花錢購買 那顆子彈,這也算是一種時代的進步吧。夏俊峰,僅僅為了站著擺個養家糊口的小攤,他被注射執行了死刑,留了個全屍,感謝黨國的恩典啊!

襯托著以上想站著活著的許多“悲劇”,許多跪著活著的“喜劇”卻不斷挑逗著我們的神經:余秋雨,一個本來才氣橫溢的文化人,為了幾斗米而折腰,留下了“含 淚勸告災民書”這樣的令所有文化人蒙羞的文章。王兆山,一個高居省作協主席的所謂詩人,一首“黨疼國愛,縱做鬼也幸福”的神詩,創造了馬屁文章的又一個巔 峰。胡錫進,環球時報總編,一個堅持論證屎比肉香的報人。他們雖然拋棄了站著活的尊嚴,卻換來了榮華富貴。

今日之中國,“夢”是一個牛逼的不能再牛逼的字詞了,本來最最簡單的站著活著,怎麼就成為了中國人最遙不可及的夢想了呢?如果不是,今天的作文題目就不可 能是這樣的一個題目,在一個正常的社會,站著活著是一個再正常不過的事情了,能夠站著,這個世界上沒有人願意跪著。出題的老師想必也為此困惑,本來是教書 育人的老師,現在成了應試教育這輛戰車上的一個道具或者說是幫兇,學習的目的早已經不是學習知識造福人類這麼單純了,老師的榮譽與收入都和升學率捆綁在了 一起,為了升學率與收入,老師都跪下了,跪在了現實的利益與權力面前。但是,你們既然已經跪下了,為什麼還用這種趙構指鹿為馬的二逼遊戲來挑逗你們的學生 們呢?學生如果站著寫這篇作文,零分估計是跑不掉的,但是,跪著寫站著的讚歌,你們不覺得這樣很殘忍嗎?

我深深地知道,我今天坐在這裡來作這樣一篇作文,我所背負的責任,這是我十二年的寒窗苦讀的艱辛,這是我農民工父母縮衣節食,望子成龍的殷切期盼。這是我 的未來是在工地上搬磚頭還是坐到有空調的寫字樓裡瀟灑最關鍵的時刻。以我的文采,如果你們出一道風花雪月的文章,我劃拉幾筆就對付了,可是,既然你們出了 這樣一個嚴肅的題目,我今天就豁出去得零分大聲地對全世界說:在今天的中國,站著相比於跪著,意味著高考作文得零分,未來只有去搬磚頭。意味著活著艱難甚 至失去生命,如夏俊峰。老師如果站著教書育人,就會失去心愛的講堂,因為這樣會影響升學率。醫生如果站著救死扶傷,他就會被其他收受醫藥廠家回扣的醫生排 擠而失去醫生的工作。員警如果站著執法如山,他就會被貪贓枉法的上司“休假式治療”。在中國,站著不但不能擁有整個世界,恰恰相反,你將失去整個世界,包 括愛你的親人和朋友

也許在很久以後的未來,我們的孩子的孩子們的時代了,那時候自由之光普照大地,每一個站著的人們,或面朝大海,或面朝松濤,能夠大聲地發出沒有強權脅迫的聲音,這聲音,比擁有整個世界還令人期待,令人嚮往!!!

老師:有站著的自由,難道不比擁有整個世界更重要嗎?

此篇要點

  • 期末要繳交本課程學期心得,採以小組繳交。
  • 詳細不明,所以可以個別心得知後彙整?還是著手類似報告書的方式進行?
  • 講得再多、心得再多,通通只不過是理論、理想層面。這些對於我們的反思並沒有任何意義,充其量就是知道,然仍不會去實踐的現實,處事圓滑就是這麼回事。
  • 乃屬反社會化一派

課程收錄

第 1 週 課程簡介簡報

所有企業都是誘拐犯,

企業製造商品,開始讓我們這些生活在這個世代的人不知不覺地習慣它,不知不覺地在任何情況下被催眠去購買。在這樣的情況下,很多文化節日中,什麼節日要過什麼樣的活動、要買什麼樣的禮物早已是商人們的目標所在,很多項目早已「被消費」而我們對於發自自己的想法就越來越少,接受商人們的建議,忘了自己想要做得事情,最後就認為自己根本沒有必要去做那些事情。

「便利即是一切,大家都這麼做,為什麼要與他人相異?」

第 2 週 當代消費社會的來臨簡報

在我眼前所見,這一切都是在催眠,「正因為我們更容易見到彼此,使得我們更在乎彼此。」這一個弱點被商人們抓得死死,逐漸地商品不只有生活基礎所需,需要一個突顯自我的代號,而效果最為顯著的就是使用的物品。

一個人使用什麼商品、習慣參與或在哪一個環境,將成為一個人的特徵,如果沒有這些特徵,對於自我存在的認同就會迷失。在過往的人類中,忙碌使得他們少有時間去思考這些問題,因此將會自然地演化出他們的特徵,而在現今就不同,我們具有額外的時間來裝扮自己,但是裝扮則是由別人來決定,而我們則是選擇消費。這表示著什麼?-將不具有特徵,只是個複製。

即使包裝地再好,但我們卻沒有擁有自己。

第 3 週 消費社會學的理論介紹簡報

「認同」是行為的最終目標,消費則是在行為過程中的描述,而消費使否能體現於現實?這並不全然。如果為追求理想而產出的理念,中間歷經的辛苦算是消費嗎?我們的理念也是需要被認同的!但是這卻不算是消費行為,「努力」一詞難道就是在消費以外的存在。

我就是那麼一個異教徒,因為堅信別人不認同的理念。

炫耀性消費這的確令人討厭,這一切的價值觀全都錯亂,「擁有的確令人忌妒,沒有仍可令人輕鬆。」但是我們都是受虐狂,不斷地想要擁有,更增添了自己的憂愁。天生沒有憂愁感測器的人也是存在於世的,這與生長背景有關,通常是生活富裕或者沒有經歷過巨大挫折者。

第 4 週 商品、符號象徵與廣告簡報

對於一個人的第一印象,如果從「他/她個性很好、思考很機靈 …」到「他/她有 XXX 商品、用什麼、穿什麼 …」那明顯地,我們將開始利用商品來聯想到一個人。

廣告是企業推銷產品的唯一手法,即使是老字號的商品,雖然不用多新奇的廣告內容,但仍需要一段時間就出來宣傳一下 (通常是很長一段時間)。因為廣告效果在世代繼承方面沒有顯著的效果,在每一個世代所偏好的內容不同,因此廣告也必須跟著世代掛勾,這也是為什麼廣告層不窮地想要抓住新的世代來購買他們的商品。

廣告面相不斷地針對年輕族群,甚至對小孩下手,這些在短時間內看不出影響所在,但是長期對於價值觀培養是有一定影響,這可怕之處只有成年人才明白,新的廣告便對成年人的影響力並不高,但是只要從小還是培養 (調教) 將可以終生受用,這是一場可怕的催眠實驗。

如果人類是有智慧的生物,那小孩到底算不算人類。

第 5 週 消費者、文化資本與生活風格簡報

講到情感消費,可謂是情有獨鍾,又或者是曾經因為人生歷史事件而去接觸商品,讓人流連忘返的回憶,而標記物恰好是商品。那種浪漫的事情是多麼崇高啊!一生所追尋得就是這一類型的事情,當然指得並不是黑歷史。

一個人的品味到底有多重要?品味將會反映在生活周遭,買什麼用什麼、會交到什麼朋友 … 等,這一切會從品味著手,而也會有想要轉移目標而改變自己品味的情況,那種契機同時也是消費手段,因此企業也會嘗試將大眾的願景改變,來達到商品推銷。

第 6 週 日本 kawaii 流行文化與消費簡報李世暉

第 7 週 全球化、跨國公司與消費簡報

對課程的心得反思

以上只是部分的課堂筆記,看著其他人寫的心得,我想這應該是要寫對於這門課的心得。我選這門課的原因既不是因為學分不夠,也不是提升學期排名推研究所用途。如果事實如此,這門課就成為被消費的對象,無緣無故地,我們被學校催眠要修這些課程,學校企業也是很可怕的象徵。會有這樣的想法是在修這門課之前就有,而在修這門課又有更加地加深信心,這一切的看法只是單純來自於一個反社會化的怪人,不能大聲說出任何課程的好壞,但增加的是經驗與觀感,必須保有自己的看法,增加思考突變性,否則就只是被世間催眠的對象。

Read More +

UVa 11638 - Temperature Monitoring

Problem

We have a device to monitor temperature. After configuring it, we place it inside the chamber whose temperature we wish to monitor. The device is equipped with four alarms each of which can be configured differently. The Alarms are identified by the numbers 1, 2, 3 and 4. The device takes a reading of its surrounding at a regular interval.

In this problem you will be simulating the behavior of such a device.

我們有一個監測溫度裝置,在安裝配置後,將其放入所要監控溫度的室內。這個裝置共有四個警報器,分別編號為 1, 2, 3, 4,這些警報器將會每隔固定一段時間進行溫度檢測。
在這個問題中,請模擬這裝置的行為。

Input

The first line of input contains a positive integer T<101, which denotes the number of test cases. Each case consists of several lines which are described below.

輸入第一行為測資筆數 T (T < 101)

The first line contains a positive integer M, which denotes the measurement interval. That is, the device takes a reading every M seconds.

每一組測資第一行為一個正整數 M,表示裝置每隔 M 秒會進行偵測。

The second line contains a non-negative integer S, which denotes the ‘Startup delay’. This is the amount of time that the device will remain idle after placing inside the chamber before it takes its first reading. The device will instantly take a reading when the ‘Startup delay’ ends.

第二行為一個非負整數 S,表示裝置在前 S 秒正在安裝,這段時間機器將不會進行偵測,在安裝完後,將會立即地進行檢測。

The third line contains four integers. The integers give the threshold temperature for alarm 1,2,3,4 respectively. Here threshold temperature means, when a recorded temperature crosses this temperature the corresponding alarm will be triggered.

第三行會有 4 個正整數,分別表示警報器 1, 2, 3, 4 的警報閥值 (根據閥值進行溫度比較)

The fourth line contains a non-negative integer C. The least significant 8 bits of this integer represents the configurations of the four alarms. The rightmost 4 bits (bit 0 to 3) determine if the alarms are enabled(bit value 1) or disabled(bit value 0). For example, if the bits are set as 0011, this means Alarm 1 and 2 are enabled and Alarm 3 and 4 are disabled. If an alarm is disabled, it will never be triggered.

第四行將會有一個非負整數 C,用最低的 8 個 bits 表示警報器的設定,最右邊的 4 個 bits (bit 0 to bit 3) 表示警報器是否有啟動 (1 表示有啟動,反之則否),例如 0011 表示警報器 1, 2 被啟動,3, 4 則沒有被啟動。如果警報器沒有被啟動,則將不會被觸發。

The next 4 bits(bits 4 to 7) determine the triggering type of each alarm. A value of 0 means, it’s a low trigger and a value of 1 means it’s a high trigger. For example, if the bits are set as 1100, this means Alarm 1 and 2 are set for low trigger and Alarm 3 and 4 for high trigger. Here high trigger means if a recorded temperature is above the set threshold temperature for an alarm, it will be triggered. Similarly, a Low trigger means if a recorded temperature is below the set threshold temperature for an alarm, that alarm will be triggered.

接下來的 4 個 bits 將會決定警報器的類型,亦即表示 1 高觸發 (大於閥值觸發) 0 表示低觸發 (低於閥值觸發)。例如 1100,警報器 1, 2 將會是低觸發,3, 4 則會是高觸發。

The fifth line contains a positive integer K<=100. The following K lines contain a pair of integers each in the format time temp. Here time represents the duration of a period with constant temperature and temp indicates the temperature of the environment in that period. Note that, time is always positive. The time value of first pair indicates the period immediately following the placement of the device inside the environment to be monitored. Successive time values indicate the duration of periods in the order they occur. The temperature at the border regions is considered to be that of the period just ending. Also, the temperature at the very beginning is that of the first period. Every value in the input will fit in 32 bit signed integer.

第五行將會有一個正整數 K,表示接下來依序發生的時間情況。將會從時間 0 開始,依序播報 (duration, temp) 表示新的溫度持續多久 (duration)。假設所有數據皆可以在 32 bits 內。

Output

For each case of input, there will be one line of output. It will first contain the case number, followed by the triggering status of each of the four alarms. The triggering status will contain four strings of either yes or no, separated by a space. The first string will be yes if alarm 1 was triggered at least once and no otherwise. The second string will be the status of alarm 2 and so on. Look at the sample output for exact formatting.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
5
5
5 10 15 20
15
1
5 15
1
0
5 10 15 20
7
2
10 15
10 20

Output for Sample Input

1
2
Case 1: no no no yes
Case 2: no no no no

Solution

題目相當令人討厭,因為區間涵蓋沒有講得很清楚。

但是最後可以明白的是

[ti, tj][tj, tk] 其中 ti < tj < tk,我們在討論觸發的時候,端點是需要被考慮的。

詳細操作,詳見代碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <stdio.h>
int main() {
int testcase, cases = 0;
int M; /* the device takes a reading every M seconds. */
int S; /* The device will instantly take a reading when the ‘Startup delay’ ends. */
int threshold[4]; /* */
int C; /* */
int enable[4], trigger[4]; /* trigger 0 <, 1 > */
int K, time, temp;
scanf("%d", &testcase);
while(testcase--) {
scanf("%d", &M);
scanf("%d", &S);
for(int i = 0; i < 4; i++)
scanf("%d", &threshold[i]);
scanf("%d", &C);
for(int i = 0; i < 4; i++)
enable[i] = (C>>i)&1;
for(int i = 4; i < 8; i++)
trigger[i - 4] = (C>>i)&1;
int result[4] = {};
int now_time = 0, L, R;
scanf("%d", &K);
while(K--) {
scanf("%d %d", &time, &temp);
L = now_time;
R = now_time + time;
if(R < S) {
} else {
int last_read = R / M * M;
if(L <= last_read && last_read <= R && last_read >= S) {
for(int i = 0; i < 4; i++) {
if(trigger[i] == 0) {
result[i] |= (temp < threshold[i])&enable[i];
} else {
result[i] |= (temp > threshold[i])&enable[i];
}
}
}
}
now_time = R;
}
printf("Case %d:", ++cases);
for(int i = 0; i < 4; i++)
printf(" %s", result[i] ? "yes" : "no");
puts("");
}
return 0;
}
Read More +