5-1 代碼對齊(UVa 1593)
不難,按行讀取,然後stringstream輸入到vector<string>那裏去,算出行最大單詞數,再算出列單詞最大寬度,然後就可以格式化輸出了;
#include<iostream> #include<string> #include<algorithm> #include<vector> #include<cstdio> #include<sstream> using namespace std; const int maxn = 1000 + 5; int len[180]; int main() { vector<string> code[maxn]; string temp; int n = 0, m = 0; for (n = 0; getline(cin, temp); n++) { stringstream ss(temp); while (ss >> temp) code[n].push_back(temp); if (code[n].size() > m) m = code[n].size(); } for (int i = 0; i < n; i++) for (int j = 0; j < code[i].size(); j++) if (code[i][j].size()>len[j]) len[j] = code[i][j].size(); for (int i = 0; i < n; i++) { for (int j = 0; j < code[i].size(); j++) { cout << code[i][j]; if (j != code[i].size() - 1) for (int k = code[i][j].size(); k <= len[j]; k++) putchar(‘ ‘); } putchar(‘\n‘); } return 0; } /* start: integer; // begins here stop: integer; // ends here s: string; c: char; // temp */
UVa1593
5-2 Ducci序列(UVa 1594)
簡單模擬,直接按要求模擬就好了,用vector<int>存n元組,弄個zero的n元組用於特判ZERO的情況,set判重;
#include<iostream> #include<cstdio> #include<algorithm> #include<map> #include<vector> #include<string> #include<set> using namespace std; int main() { int T; cin >> T; while (T--) { int n; cin >> n; vector<int> temp,temp2,zero; temp.resize(n); zero.resize(n); for (int i = 0; i < n; i++) zero[i] = 0; set<vector<int>> sv; for (int i = 0; i < n; i++) { cin >> temp[i]; } sv.insert(temp); temp2 = temp; for (int t=0;t<1000;t++) { for (int i = 0; i < n; i++) temp2[i] = abs(temp[i%n] - temp[(i + 1) % n]); if (temp2 == zero) { cout << "ZERO\n"; break; } else if (sv.count(temp2)) { cout << "LOOP\n"; break; } sv.insert(temp2); temp = temp2; } } return 0; }
UVa1594
5-3 卡片游戲(UVa 10935)
簡單模擬,按要求模擬一下就好了;
#include<iostream> #include<queue> #include<vector> using namespace std; int main() { int n; while (cin >> n&&n) { queue<int> que; for (int i = 1; i <= n; i++) que.push(i); cout << "Discarded cards:"; for (int i = 0; i < n - 1; i++) { int temp = que.front(); cout <<" "<< temp; if (i != n - 2) cout << ‘,‘; que.pop(); temp = que.front(); que.pop(); que.push(temp); } cout << endl << "Remaining card:" <<" "<< que.front() << endl; } return 0; }
UVa10935
5-4 交換學生(UVa 10763)
用map<pair<int,int>,int>模擬匹配,每次讀取一個同學從A換到B的請求,然後尋找有沒人要從B換到A,如果有的話,就對應map的值減1,沒有的話,就把這個同學的請求加入到map裏面去,全部數據讀取完畢后,掃一遍map裏面的值,衹要有一個>0,就代表有人沒有交換到,輸出NO,否則輸出YES;
#include<iostream> #include<set> #include<utility> #include<cstdio> #include<map> using namespace std; typedef pair<int, int> P; int main() { int n; while (cin >> n&&n) { map<P, int> mp; int x, y; for (int i = 0; i < n; i++) { scanf("%d%d", &x, &y); P temp = make_pair(y, x); if (mp.count(temp)) if (mp[temp]>0) { mp[temp]--; continue; } else mp.erase(temp); temp = make_pair(x, y); if (!mp.count(temp)) { mp[temp] = 1; continue; } mp[temp]++; } map<P, int>::iterator it; bool off = true; pair<P, int> temp; for (it = mp.begin(); it != mp.end(); it++) { temp = *it; if (temp.second > 0) off = false; } if (off) cout << "YES\n"; else cout << "NO\n"; } return 0; }
UVa10763
5-5 複合詞(UVa 10391)
= =暴力,把輸入全部存入set<string>裏面去,讀取完畢后,從set的開始遍歷到結束,然後對於每個單詞,從第一個字幕開始,分成兩半,分別在set裏面查找,如果都找得到,那麽就是複合詞,并且輸出;
#include<iostream> #include<cstdio> #include<map> #include<string> #include<set> using namespace std; int main() { set<string> ss; string temp; while (cin >> temp) ss.insert(temp); set<string>::iterator it; for (it = ss.begin(); it != ss.end(); it++) { temp = *it; for (int i = 1; i < temp.size() - 1; i++) if (ss.count(temp.substr(0, i)) && ss.count(temp.substr(i))) { cout << temp << endl; break; } } return 0; }
UVa10391
5-6 對稱軸 (UVa 1595)
嗯,輸入都是整數,那麽問題來了,1和3的對稱軸是2,但是1和2的對稱軸是1.5= =那麽的話,還是直接整數解決好了,分類討論,都用set<pair<int,int>還存點,如果對稱軸是整數的話,那麽直接枚舉每個人,看下是否都能找到對稱的另一個點,沒有的話就NO,如果對稱軸是x.5的情況,那麽先處理一下x.5(+-)0.5這兩條綫上的點是否對稱的情況,如果對稱的話,再用上面那種方式,求剩下點;現在想想的話,其實x.5這種情況也可以直接忽略對稱軸,然後求對稱的點,那樣的話,代碼可以減十多行?
#include<iostream> #include<set> #include<utility> #include<cstdio> using namespace std; typedef pair<int, int> P; const int maxn = 10005; int main() { int T; cin >> T; while (T--) { int n; cin >> n; set<P> sp; int x, y; int left = maxn, right = -maxn; int lefth = maxn, righth = -maxn; while (n--) { scanf("%d%d", &x, &y); P temp = make_pair(x, y); if (x < left) left = x; if (x > right) right = x; if (y < lefth) lefth = y; if (y > righth) righth = y; sp.insert(temp); } /*set<P>::iterator it; for (it = sp.begin(); it != sp.end(); it++) { P temp = *it; cout << temp.first << " " << temp.second << endl; }*/ //cout << left << " " << right << endl; if ((left + right) & 1) { int mid1 = (left + right) / 2; int mid2 = mid1 + 1; bool off = true; for (int i = -lefth; i < righth; i++) { if (sp.count(make_pair(mid1, i))) { if (!sp.count(make_pair(mid2, i))) { off = false; break; } else { sp.erase(make_pair(mid1, i)); sp.erase(make_pair(mid2, i)); } } } if (!off) { cout << "NO\n"; continue; } set<P>::iterator it; P temp; for (it = sp.begin(); it != sp.end(); it++) { temp = *it; if (temp.first < mid1) { if (!sp.count(make_pair(mid2 + mid1 - temp.first, temp.second))) { off = false; break; } } else { if (!sp.count(make_pair(mid1 - temp.first + mid2, temp.second))) { off = false; break; } } } if (!off) { cout << "NO\n"; continue; } else { cout << "YES\n"; continue; } } else { int mid = (left + right) / 2; bool off = true; for (int i = lefth; i < righth; i++) if (sp.count(make_pair(mid, i))) { sp.erase(make_pair(mid, i)); } set<P>::iterator it; P temp; for (it = sp.begin(); it != sp.end();it++) { temp = *it; if (temp.first < mid) { if (!sp.count(make_pair(mid - temp.first + mid, temp.second))) { off = false; break; } } else if (!sp.count(make_pair(2 * mid - temp.first, temp.second))) { off = false; break; } } if (!off) { cout << "NO\n"; continue; } else { cout << "YES\n"; continue; } } } return 0; }
UVa1595
5-7 打印隊列(UVa 12100)
額,一個簡單模擬,然後N<=100,複雜度O(N^2);讀取的時候,計算每個優先級的打印個數,并且計算出最高優先級,然後模擬打印過程,如果當前打印任務不是關注任務,并且優先級等於當前最大優先級,就打印掉(刪掉),如果是關注的打印任務并且等於當前最大優先級,就推出循環,然後輸出計數器的數字;
#include<iostream> #include<cstdio> #include<utility> #include<queue> using namespace std; typedef pair<int, bool> P; int main() { int T; cin >> T; while (T--) { queue<P> qp; int n, m, t; cin >> n >> m; int num[10] = { 0 }; int maxx = 0; for (int i = 0; i < n; i++) { cin >> t; if (i == m) qp.push(make_pair(t, true)); else qp.push(make_pair(t, false)); if (t > maxx) maxx = t; num[t]++; } int cnt = 0; P temp = qp.front(); //cout << temp.first<<" "<<temp.second<<" "<<maxx << endl; for (; !(temp.second)||temp.first!=maxx;) { if (temp.first == maxx) { num[maxx]--; if (num[maxx] == 0) for (; !num[maxx]; maxx--) ; cnt++; qp.pop(); temp = qp.front(); } else { qp.push(make_pair(temp.first, temp.second)); qp.pop(); temp = qp.front(); } } cnt++; cout << cnt << endl; } return 0; }
UVa12100
5-8 圖書管理系統(UVa 230)
相比于上面的題目,這題的模擬難度略難一點,并且題意不太懂,然後翻譯了下,并且百度了下相關題解,想看別人翻譯的題意的,結果好像看到有人說這題用不上set,map這些STL的東西,用struct過的,讀懂題目之後,就不難做了。嗯,第一個麻煩,提取輸入的書本的信息,可以看到,書名用“”引起來了,然後作者的前面有個by,就靠這兩個加string的find和substr就可以提取出書本信息了,然後用map<string,pair<string,string>>就可以形成書名到書名和作者的映射了,然後弄幾個set<pair<string,string>>來分別記錄書架上的,借出去的,還回來的,然後模擬一下,借書和還書的過程不難,整理的時候,略微有些麻煩(自身水平有限),從還回來的set裏面的第一本還是還原,先插到書架上,然後在書架上查那本書的位置,反向迭代器是爲了判斷是不是第一本,而且好返回上一本的信息(因爲我用正向迭代器--的話,貌似遇到了困難),找到了之後,就輸出信息就好了,尷尬的是,當時代碼好像弄多了個s1,然而過程卻沒用到= =;
#include<iostream> #include<cstdio> #include<string> #include<map> #include<set> #include<vector> using namespace std; struct Lan { string book, author; bool off; }; bool operator <(const Lan& t1,const Lan&t2) { if (t1.author != t2.author) return t1.author < t2.author; else return t1.book < t2.book; } int main() { string s, t; map<string, Lan> mp; set<Lan> sl, now, brrow, rt; while (getline(cin, s)) { if (s == "END") break; int begin = s.find(‘"‘); int end = s.find(‘"‘, begin + 1); int by = s.find("by", end + 1); Lan temp; temp.book = s.substr(begin, end+1); temp.author = s.substr(by+2); sl.insert(temp); now.insert(temp); mp[temp.book] = temp; } for (;;) { cin >> s; if (s == "END") break; if (s == "SHELVE") { set<Lan>::iterator it; for (it = rt.begin(); it != rt.end(); it++) { now.insert(*it); set<Lan>::reverse_iterator reit; for (reit = now.rbegin(); reit != now.rend(); reit++) { if (reit->book == it->book&&reit->author == it->author) break; } Lan temp = *reit; if (++reit != now.rend()) { Lan temp2 = *reit; cout << "Put " << temp.book << " after " << temp2.book << endl; } else cout << "Put " << temp.book << " first\n"; } rt.clear(); cout << "END\n"; continue; } if (s == "BORROW") { getline(cin, t); int begin = t.find(‘"‘); int end = t.find(‘"‘, begin + 1); t = t.substr(begin, end); if (now.count(mp[t])) { brrow.insert(mp[t]); now.erase(mp[t]); } else { } continue; } if (s == "RETURN") { getline(cin, t); int begin = t.find(‘"‘); int end = t.find(‘"‘, begin + 1); t = t.substr(begin, end); if (brrow.count(mp[t])) { brrow.erase(mp[t]); rt.insert(mp[t]); } } } return 0; }
UVa230
5-9 找bug (UVa 1596)
其實是一個不難的,可能是因爲當時心情問題或者現在碼力略有提升,所以當時覺得有些難;兩種bug,一種是越界,一種是使用了未初始化的變量。對於第一種bug,直接建個val數組,然後存放聲明的時候的數組size,對於第二種bug,用map映射,檢查是否有初始化;然後這題的難點,其實是在提取字符串這裏,因爲有a[b[c[1]]]這樣的語句,故要一層一層解釋,觀察代碼可以發現,左邊肯定有一個變量名,然後是變量的下標(可以是一個數組元素),右邊是一個數值(可能是一個數組的值),所以,左邊提取下標的操作和右邊讀取數值的操作,其實是同一個操作,然後遞歸解決,如果是數字的話,循環讀取數字的值,如果遇到是一個數組的元素,那麽讀取數組名,再讀取該數組的下標進行遞歸,并且每次讀取數組的元素的值之後,都要檢查,有沒有越界,把這兩個值讀取完之後,判斷這個變量賦值操作的數組的下標有沒越界,沒有的話,就進行賦值;
#include<iostream> #include<cstdio> #include<string> #include<string.h> #include<sstream> #include<vector> #include<map> #include<set> #include<utility> #include<queue> #include<stack> #include<algorithm> #include<cstdlib> using namespace std; typedef long long ll; typedef pair<int, int> P; #define mp make_pair #define pb push_back const int maxc = 26*2; const int maxn = 88; int val[maxc],num; map<int, int> m[maxc]; char line[maxn],ch; int get_id(char c) { return (islower(c)) ? c - ‘a‘ : c - ‘A‘ + 26; } bool check(int id, int v) { //int id = get_id(ch); if (val[id]==-1||v >= val[id] || v < 0) return false; else if (m[id].find(v) == m[id].end()) return false; return true; } int get_num(char *s) { if (isalpha(*s)) { int id = get_id(*s); int num = get_num(s + 2); if (check(id, num)) return m[id][num]; else return -1; } else { int num = 0; while (*s != ‘\0‘ && *s != ‘\n‘ && *s != ‘]‘) { num = num * 10 + (*s - ‘0‘); ++s; } return num; } } int main() { while (fgets(line, maxn, stdin) && strcmp(line, ".\n") != 0) { memset(val, -1, sizeof(val)); for (auto &t : m) t.clear(); int off = true; int count = 0; do { if (strchr(line, ‘=‘) == NULL) { sscanf(line, "%c[%d]", &ch, &num); val[get_id(ch)] = num; ++count; } else { char *eq = strchr(line, ‘=‘); int right = get_num(eq + 1); int left = get_num(line + 2); int id = get_id(*line); ++count; if (val[id] == -1 || left >= val[id] || left < 0 || right == -1) { printf("%d\n", count); off = false; break; } else m[id][left] = right; //cout << left << "**" << right << endl; } } while (off&&fgets(line, maxn, stdin) && strcmp(line, ".\n") != 0); if (!off) while (fgets(line, maxn, stdin) && strcmp(line, ".\n") != 0); else puts("0"); //for (auto &t : val) // cout << t << endl; } return 0; }
UVa1596
5-10 在Web中搜索(UVa 1597)
這題其實也不難,對於這題,至少有兩種方法,第一種,就是我寫的這種暴力莽過去,第二種是按照題目指導的方法,直接寫就好了;
其實我是讀過題目,看了題目說的做法的,不過我覺得直接寫就可以A了,所以就這樣生生的A了= =時限3s,我好像是1.5/6s過去的,在WA了一兩次之後,我去查了下題意,看到了別人的題解裏面說,祇看劉老師說的題意直接寫會超時(大概是估計複雜度覺得不可過,或者優化不夠),具體做法是這樣的,全部文章存到一個二維char數組裏,fgets按行讀取,同時記錄每篇文章從該數組的第幾行開始,第幾行結束,并且處理每一行成祇含小學字母到另一個數組裏面去,并用vector<pair<int,int>>儲存每一行的每個單詞的開始下標和長度,讀取完畢后,也全部預處理完畢了,然後開始讀入查詢,對於每個查詢,從第一篇查到最後一篇,查詢的時候,祇和長度和查詢的單詞長度相等的匹配,并且用strcmp匹配,把找到的關鍵行數存到一個set<int>裏面,既可以存行數,又自動去重,每篇文章查完就輸出,就這樣莽了過去。
在這個題目裏,WA了3次?問題源于自己一個傻逼的"優化",就是對於查詢的OR/AND,一開始我是打算用兩個bool代表兩個單詞的查找狀態,然後用||/&&判斷的,後來發覺合在一起代碼也短不了,所以又分開了,分開了之後,對於OR反而直接用||來判斷,忘了||是短路運算符,所以遇到左邊查找成功后,右邊就沒查找了,那麽輸出行數的時候,就會少掉部分(因爲存在一些左右邊都在同一行的)右邊的行,導致WA;
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<sstream> #include<vector> #include<map> #include<set> #include<utility> #include<queue> #include<stack> #include<algorithm> #include<cstdlib> using namespace std; typedef long long ll; typedef pair<int, int> P; #define mp make_pair #define pb push_back const int maxn = 1505; const int maxlen = 85; char s[maxn][maxlen], t[maxn][maxlen]; int cnt = 0; P doc[100]; vector<P> line[maxn]; bool find_str(int idx,const char *str,set<int> &ans) { int start = doc[idx].first, over = doc[idx].second,len=strlen(str); //cout << len << endl; bool off = false; for (int i = start; i < over;++i) for (int j = 0; j < line[i].size(); ++j) { if (line[i][j].second != len) continue; if (strcmp(t[i] + line[i][j].first, str) == 0) { ans.insert(i); //puts(s[i]); off = true; break; } } return off; } void print(set<int> &ans) { for (auto &i : ans) printf("%s", s[i]); } int main() { char c; int n; scanf("%d%c", &n, &c); for (int i = 0; i < n; ++i) { doc[i].first = cnt; while (fgets(s[cnt], maxlen, stdin)) { if (strcmp(s[cnt], "**********\n") == 0) { doc[i].second = cnt; break; } int len = strlen(s[cnt]); int temp = 0; for (int j = 0; j < len; ++j) { if (isalpha(s[cnt][j])) { t[cnt][j] = tolower(s[cnt][j]); ++temp; } else { if (temp) line[cnt].pb(mp(j - temp, temp)); temp = 0; t[cnt][j] = ‘\0‘; } } ++cnt; } } int m; scanf("%d%c", &m, &c); for (int i = 0; i < m; ++i) { string str[3]; getline(cin, str[0]); stringstream ss(str[0]); for (int j = 0; ss >> str[j]; ++j); int temp = 0; for (int j = 0; j < n; ++j) { set<int> ans; if (str[0].compare("NOT") == 0) { if (!find_str(j, str[1].c_str(), ans)) { if (temp) puts("----------"); for (int k = doc[j].first; k < doc[j].second; ++k) printf("%s", s[k]); ++temp; } } else if (str[1].compare("AND") == 0) { if (find_str(j, str[0].c_str(), ans) && find_str(j, str[2].c_str(), ans)) { if (temp) puts("----------"); print(ans); ++temp; } } else if (str[1].compare("OR") == 0) { bool t1 = find_str(j, str[0].c_str(), ans), t2 = find_str(j, str[2].c_str(), ans); if (t1 || t2) { if (temp) puts("----------"); print(ans); ++temp; } } else { if (find_str(j, str[0].c_str(), ans)) { if (temp) puts("----------"); print(ans); ++temp; } } } if (!temp) puts("Sorry, I found nothing."); puts("=========="); } return 0; }
UVa1597
5-11 更新字典(UVa 12504)
這題其實并不難,就是不知道當時爲什麽覺得有些難(或者煩?),然後就沒做了= =很簡單,首先觀察一下輸入,會看到格式很標準,直接把不是alpha和num的替換成‘ ‘就好了,這樣的話,用stringsteam的話,就可以很自然的把key和val讀入到兩個string裏面了,然後用map<string,string>儲存兩個字典,剩下就是對比了,對比的話,三個vector<string>分別存放增加,刪除,修改的元素,先遍歷A,在B中查,如果查到了,對比一下值,如果不一樣,就是修改鍵,如果查不到,就是刪除鍵,,然後遍歷B,在A中查,如果查不到就是新增鍵,查得到就跳過(因爲第一步的時候,就比較過了),然後就是輸出三種鍵的答案,如果發覺三種鍵儲存的vector的size都0,那麽代表沒修改,輸出No change;
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<sstream> #include<vector> #include<map> #include<set> #include<utility> #include<queue> #include<stack> #include<algorithm> #include<cstdlib> using namespace std; typedef long long ll; typedef pair<int, int> P; typedef pair<string, string> ps; #define mp make_pair #define pb push_back string s1, s2; map<string, string> m1, m2; inline void action(string &s) { for (auto &t : s) if (!isalpha(t) && !isalnum(t)) t = ‘ ‘; } inline void get_key_val(stringstream &ss, map<string, string> &ms) { string k, v; while (ss >> k) { ss >> v; ms[k] = v; } } inline void print(const vector<string> &vs, char ch) { putchar(ch); for (int i = 0; i < vs.size(); ++i) { if (i) putchar(‘,‘); cout << vs[i]; } putchar(‘\n‘); } int main() { int T; scanf("%d ", &T); while (T--) { m1.clear(); m2.clear(); getline(cin, s1); getline(cin, s2); action(s1); action(s2); stringstream ss1(s1), ss2(s2); get_key_val(ss1, m1); get_key_val(ss2, m2); vector<string> add, sub, change; for (auto &t : m1) { auto it = m2.find(t.first); if (it == m2.end()) sub.push_back(t.first); else if (it->second != t.second) change.push_back(t.first); } for (auto &t : m2) { if (m1.find(t.first) == m1.end()) add.push_back(t.first); } if (add.size()) print(add, ‘+‘); if (sub.size()) print(sub, ‘-‘); if (change.size()) print(change, ‘*‘); if (!add.size() && !sub.size() && !change.size()) puts("No changes"); putchar(‘\n‘); } return 0; }
UVa12504
嗯,目前就到此爲止了,本章剩下的習題還麽做出來,基本上覺得麻煩,細節不清楚,所以沒做,等到下次心比較靜的時候,回頭看翻譯的題面,理清思路A掉。寫了前11題的題解,略有所感= =發覺,以前還是too young,有些代碼可以優化下長度,或者寫得更優美一點,不過,估計是那時候還沒開始用C++11的一些新特性吧,以及現在重新看了題意,之前的代碼,寫的記錄,確實加深了一些印象,不至於做了一段時候就忘掉太多= =