算法竞赛入门经典(第二版)-刘汝佳-第五章 C++与STL 习题(13/16)

说明

本文是我对第五章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);                         
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值