-習題(1-11)待續
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了-習題(1-11)待續相关的知识,希望对你有一定的参考价值。
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
*/
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
嗯,目前就到此爲止了,本章剩下的習題還麽做出來,基本上覺得麻煩,細節不清楚,所以沒做,等到下次心比較靜的時候,回頭看翻譯的題面,理清思路A掉。寫了前11題的題解,略有所感= =發覺,以前還是too young,有些代碼可以優化下長度,或者寫得更優美一點,不過,估計是那時候還沒開始用C++11的一些新特性吧,以及現在重新看了題意,之前的代碼,寫的記錄,確實加深了一些印象,不至於做了一段時候就忘掉太多= =
以上是关于-習題(1-11)待續的主要内容,如果未能解决你的问题,请参考以下文章
Python开发 基礎知識 3.類別&方法 (bool & str) (未完待續)