文章目录
- 说明
- 习题
-
- 习5-1 UVA 1593 代码对齐(vector)
- 习5-2 UVA 1594 Ducci 队列
- 习5-3 UVA 10935 卡片游戏(queue)
- 习5-4 UVA 10763 交流生(排序)
- 习5-5 UVA 10391 复合词(查找、set)
- 习5-6 UVA 1595 对称轴(排序)
- 习5-7 UVA 12100 打印队列(queue)
- 习5-8 UVA 230 图书管理系统(set、map)
- 习5-9 UVA 1596 调试(map)
- 习5-10 UVA 1597 在互联网中搜索(map、set、vector等)
- 习5-11 UVA 12504 更新字典(map)
- 习5-12 UVA 511 Do You Know the Way to San Jose?(排序、map、sort、unique等)
- 习5-13 UVA 822 客户中心(模拟,vector、map)
- 习5-14 UVA 1598 交易所(未尝试)
- 习5-15 UVA 12333 斐波那契的复仇(未尝试)
- 习5-16 UVA 212 医疗设备利用(未尝试)
说明
本文是我对第五章16道习题的练习总结,建议配合紫书——《算法竞赛入门经典(第2版)》阅读本文。
另外为了方便做题,我在VOJ上开了一个contest,欢迎一起在上面做:第五章习题contest
如果想直接看某道题,请点开目录后点开相应的题目!!!
习题
习5-1 UVA 1593 代码对齐(vector)
思路
此题的重点在于读入数据部分,读取每一行我用了getline,然后再用stringstream将该行数据分割成字符串vector数组。请读者自行看代码体会。
输出就比较简单了,不足最大长度的用空格补齐。
代码
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1000;
const int LEN = 180;
int n;
vector<string> vs[N];
int w[LEN];
int main(void)
{
n = 0;
string line, s;
memset(w, 0, sizeof(w));
while (getline(cin, line)) {
stringstream stm(line);
int i = 0;
while (stm >> s) {
w[i] = max(w[i], (int)(s.size()));
i ++;
vs[n].push_back(s);
}
n ++;
}
for (int i = 0; i < n; i ++) {
int k = vs[i].size();
for (int j = 0; j < k-1; j ++) {
cout << vs[i][j];
for (int r = 0; r <= w[j]-vs[i][j].size(); r ++)
printf(" ");
}
cout << vs[i][k-1] << endl;
}
return 0;
}
习5-2 UVA 1594 Ducci 队列
思路
没看出来本题和本章主题C++与STL有什么联系。
思路很简单,循环1000步,每步检查是否到终止条件(全0),提前达到终止条件则为ZERO,否则为LOOP。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 15;
int n, a[N];
bool is_zero()
{
for (int i = 0; i < n; i ++) {
if (a[i]) return false;
}
return true;
}
void change()
{
int tmp = a[0];
for (int i = 0; i < n-1; i ++)
a[i] = abs(a[i] - a[i+1]);
a[n-1] = abs(a[n-1] - tmp);
}
int main(void)
{
int t;
cin >> t;
while (t --) {
cin >> n;
for (int i = 0; i < n; i ++)
scanf("%d", &a[i]);
int loop = 1001;
while (loop--) {
if (is_zero()) break;
change();
}
if (is_zero()) puts("ZERO");
else puts("LOOP");
}
return 0;
}
习5-3 UVA 10935 卡片游戏(queue)
思路
看题目描述就能知道是一个队列,具体细节看代码吧。
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
int main(void)
{
int n;
while (cin >> n && n) {
queue<int> q;
for (int i = 1; i <= n; i ++)
q.push(i);
printf("Discarded cards:");
while (q.size() > 2) {
printf(" %d,", q.front());
q.pop();
q.push(q.front());
q.pop();
}
if (q.size() == 2) {
printf(" %d", q.front());
q.pop();
}
printf("\n");
printf("Remaining card:");
printf(" %d\n", q.front());
}
return 0;
}
习5-4 UVA 10763 交流生(排序)
思路
记P(A,B)表示一个想从A校换到B校的学生,数组a[N]和b[N](元素类型为P)表示所有学生集合(初始内容相同)。
定义两种比较函数:cmp1表示以元素first为第一排序依据,second为第二排序依据,排序顺序都是从小到大;cmp2则是以second为第一依据,first为第二依据。
a和b分别用cmp1和cmp2排序后,如果a和b的任意第i个元素互相能对应起来,也就是满足代码中的条件:
a[i].first == b[i].second && a[i].second == b[i].first
则交换可以进行。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef pair<int, int> P;
const int N = 500000;
int n;
P a[N], b[N];
bool cmp1(P p1, P p2)
{
if (p1.first != p2.first) return p1.first < p2.first;
return p1.second < p2.second;
}
bool cmp2(P p1, P p2)
{
if (p1.second != p2.second) return p1.second < p2.second;
return p1.first < p2.first;
}
int main(void)
{
while (cin >> n && n) {
for (int i = 0; i < n; i ++)
scanf("%d%d", &a[i].first, &a[i].second);
memcpy(b, a, sizeof(a));
sort(a, a+n, cmp1);
sort(b, b+n, cmp2);
bool flag = true;
for (int i = 0; i < n; i ++) {
if (!(a[i].first == b[i].second && a[i].second == b[i].first))
{ flag = false; break;}
}
if (flag) puts("YES");
else puts("NO");
}
return 0;
}
习5-5 UVA 10391 复合词(查找、set)
思路
有两种方法可以寻找复合词:
1、枚举所有两个词的组合,查找是否则词典中;
2、枚举所有词,拆分词为s1和s2查找是否都在词典中。
词典的规模是120000,显然第二种时间复杂度低。
尽管思路很清晰,但我还是WA了很多次,最后发现是因为在打印复合词之后未break,这可能导致某个复合词被打印多次。而这个错误在示例数据中检测不出来。
这个题也可以用set,代码写起来会简单一些。
代码
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
using namespace std;
const int N = 120001;
int n;
string s[N];
int main(void)
{
n = 0;
while (cin >> s[n]) n++;
s[n] = "";
string s1, s2;
for (int i = 0; i < n; i ++) {
int m = s[i].size();
for (int j = 1; j < m; j ++) {
s1 = s[i].substr(0, j);