PAT : 团体程序设计天梯赛-练习集 L2 答案

2019/03/18 完成01-02node

2019/03/19 完成03ios

2019/03/20 完成04git

2019/03/21 完成05(unordered_set)算法

2019/03/22 完成05(手写哈希),06数组

2019/03/23 完成07性能

L2-001 紧急救援(C++11)

#include <iostream>
#include <stack>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
const int INF{0x3f3f3f3f};
int main(int argc, char *argv[])
{
    cin.sync_with_stdio(false);
    int N, M, S, D;
    cin >> N >> M >> S >> D;
    vector<int> vec(N);
    for (int i = 0; i != N; ++i)
        cin >> vec[i];
    vector<vector<intpair>> road(N);
    for (int i = 0; i != M; ++i)
    {
        int mbeg, mend, mvel;
        cin >> mbeg >> mend >> mvel;
        road[mbeg].push_back({mend, mvel});
        road[mend].push_back({mbeg, mvel});
    }
    vector<int> dijkstra(N, INF), mov(N), cross(N), mins(N);
    vector<bool> known(N, false);
    dijkstra[S] = 0;
    mov[S] = vec[S];
    cross[S] = -1;
    mins[S] = 1;
    while (1)
    {
        int minval{INF}, minindex{-1};
        for (int i = 0; i != N; ++i)
        {
            if (known[i] == false && dijkstra[i] != INF && dijkstra[i] < minval)
            {
                minindex = i;
                minval = dijkstra[i];
            }
        }
        if (minindex == -1)
            break;
        known[minindex] = true;
        for (const auto &i : road[minindex])
        {
            if (dijkstra[minindex] + i.second < dijkstra[i.first])
            {
                dijkstra[i.first] = dijkstra[minindex] + i.second;
                mov[i.first] = mov[minindex] + vec[i.first];
                cross[i.first] = minindex;
                mins[i.first] = mins[minindex];
            }
            else if (dijkstra[minindex] + i.second == dijkstra[i.first])
            {
                if (mov[minindex] + vec[i.first] > mov[i.first])
                {
                    mov[i.first] = mov[minindex] + vec[i.first];
                    cross[i.first] = minindex;
                }
                mins[i.first] += mins[minindex];
            }
        }
    }
    cout << mins[D] << ' ' << mov[D] << endl;
    stack<int> ST;
    int tD{D};
    ST.push(D);
    while (cross[tD] != -1)
    {
        ST.push(cross[tD]);
        tD = cross[tD];
    }
    bool fis = true;
    while (!ST.empty())
    {
        if (fis)
            fis = false;
        else
            cout << ' ';
        cout << ST.top();
        ST.pop();
    }
    cout << endl;
    return EXIT_SUCCESS;
}

Dijkstra算法 学习

L2-002 链表去重(C++11)

#include <iostream>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
int main(int argc, char *argv[])
{
    int beginnode, cnt;
    scanf("%d%d", &beginnode, &cnt);
    vector<intpair> LinkNode(100000);
    vector<int> book(100001);
    while (cnt--)
    {
        int beg, val, next;
        scanf("%d%d%d", &beg, &val, &next);
        LinkNode[beg] = {val, next};
    }
    int disp{-1}, dispold{beginnode}, temp{-1}, temp2{-1};
    while (beginnode != -1)
    {
        if (book[abs(LinkNode[beginnode].first)])
        {
            if (disp == -1)
                disp = temp = beginnode;
            else
            {
                LinkNode[temp].second = beginnode;
                temp = beginnode;
            }
        }
        else
        {
            if (temp2 != -1)
                LinkNode[temp2].second = beginnode;
            temp2 = beginnode;
            book[abs(LinkNode[beginnode].first)] = true;
        }
        beginnode = LinkNode[beginnode].second;
    }
    LinkNode[temp2].second = LinkNode[temp].second = -1;
    beginnode = dispold;
    if (beginnode != -1)
    {
        printf("%05d %d", beginnode, LinkNode[beginnode].first);
        beginnode = LinkNode[beginnode].second;
        while (beginnode != -1)
        {
            printf(" %05d\n%05d %d", beginnode, beginnode, LinkNode[beginnode].first);
            beginnode = LinkNode[beginnode].second;
        }
        printf(" -1\n");
    }
    beginnode = disp;
    if (beginnode != -1)
    {
        printf("%05d %d", beginnode, LinkNode[beginnode].first);
        beginnode = LinkNode[beginnode].second;
        while (beginnode != -1)
        {
            printf(" %05d\n%05d %d", beginnode, beginnode, LinkNode[beginnode].first);
            beginnode = LinkNode[beginnode].second;
        }
        printf(" -1\n");
    }
    return EXIT_SUCCESS;
}

考察数组模拟链表;上面的实现的稍有麻烦,彻底修正了链表地址,分开了两个链表;然而根据题目输出要求,这是没有必要的!能够直接开两个vector存储下两个链表的地址,以下。测试

#include <iostream>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
intpair LinkNode[100000];
int book[100001]{0};
int main(int argc, char *argv[])
{
    int beginnode, cnt;
    scanf("%d%d", &beginnode, &cnt);
    while (cnt--)
    {
        int beg, val, next;
        scanf("%d%d%d", &beg, &val, &next);
        LinkNode[beg] = {val, next};
    }
    vector<int> a, b;
    while (beginnode != -1)
    {
        if (book[abs(LinkNode[beginnode].first)])
            b.push_back(beginnode);
        else
        {
            a.push_back(beginnode);
            book[abs(LinkNode[beginnode].first)] = true;
        }
        beginnode = LinkNode[beginnode].second;
    }
    if (!a.empty())
    {
        printf("%05d %d", a[0], LinkNode[a[0]].first);
        for (decltype(a.size()) i = 1; i != a.size(); ++i)
            printf(" %05d\n%05d %d", a[i], a[i], LinkNode[a[i]].first);
        printf(" -1\n");
    }
    if (!b.empty())
    {
        printf("%05d %d", b[0], LinkNode[b[0]].first);
        for (decltype(b.size()) i = 1; i != b.size(); ++i)
            printf(" %05d\n%05d %d", b[i], b[i], LinkNode[b[i]].first);
        printf(" -1\n");
    }
    return EXIT_SUCCESS;
}

L2-003 月饼

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
using mypair = pair<double, double>;
bool mypaircompare(const mypair &a, const mypair &b)
{
    return a.second > b.second;
}
int main(int argc, char *argv[])
{
    int cnt, need;
    scanf("%d%d", &cnt, &need);
    vector<mypair> vec(cnt);
    for (int i = 0; i < cnt; ++i)
        scanf("%lf", &vec[i].first);
    for (int i = 0; i < cnt; ++i)
    {
        double temp;
        scanf("%lf", &temp);
        vec[i].second = temp / vec[i].first;
    }
    sort(vec.begin(), vec.end(), mypaircompare);
    double cost{0.0};
    for (int i = 0; i < cnt; ++i)
    {
        if (need >= vec[i].first)
        {
            need -= vec[i].first;
            cost += vec[i].first * vec[i].second;
            if (!need)
                break;
        }
        else
        {
            cost += need * vec[i].second;
            break;
        }
    }
    printf("%.2lf\n", cost);
    return EXIT_SUCCESS;
}

简单的贪心;老题目了,须要注意库存量和总售价都是浮点数,样例输入是整数具备迷惑性…哈哈 ui

L2-004 这是二叉搜索树吗?

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int array[1001]{0};
vector<int> T;
bool mir;
bool buildtree(int beg, int ed)
{
    if (beg > ed)
        return true;
    int root{array[beg]}, mid;
    int temp{beg + 1};
    if (mir)
    {
        while (temp <= ed && array[temp] >= root)
            ++temp;
        mid = temp - 1;
        while (temp <= ed && array[temp] < root)
            ++temp;
    }
    else
    {
        while (temp <= ed && array[temp] < root)
            ++temp;
        mid = temp - 1;
        while (temp <= ed && array[temp] >= root)
            ++temp;
    }
    if (temp != ed + 1)
        return false;
    bool re = buildtree(beg + 1, mid) && buildtree(mid + 1, ed);
    T.push_back(root);
    return re;
}
int main(int argc, char *argv[])
{
    int cnt;
    scanf("%d", &cnt);
    for (int i = 1; i <= cnt; ++i)
        scanf("%d", &array[i]);
    mir = false;
    bool isp{true};
    if (!buildtree(1, cnt))
    {
        mir = true;
        T.clear();
        isp = buildtree(1, cnt);
    }
    if (isp)
    {
        printf("YES\n");
        for (auto i = T.begin(); i != T.end(); ++i)
        {
            if (i != T.begin())
                putchar(' ');
            printf("%d", *i);
        }
        putchar('\n');
    }
    else
        printf("NO\n");
    return EXIT_SUCCESS;
}

根据二叉搜索树的前序遍历,输出后序遍历。由于只须要输出后序遍历,因此咱们并不须要真正的建树,按照左子树、右子树、根节点的次序把后序遍历存储下来就能够啦。spa

基础题上加了个花样,便可能是“镜像二叉搜索树”;先假定不是镜像的,遍历一次;若是遍历失败,就假定是镜像的,再尝试一次,两次都失败输出“NO”,成功就输出存储后序遍历的vector。 

L2-005 集合类似度

#include <algorithm>
#include <iostream>
#include <set>
#include <unordered_set>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
    int cnt;
    scanf("%d", &cnt);
    vector<unordered_set<int>> SET(cnt);
    for (int i = 0; i != cnt; ++i)
    {
        int ind;
        scanf("%d", &ind);
        while (ind--)
        {
            int temp;
            scanf("%d", &temp);
            SET[i].insert(temp);
        }
    }
    scanf("%d", &cnt);
    while (cnt--)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        --a, --b;
        int sum{0};
        for (const auto &i : SET[a])
            if (SET[b].find(i) != SET[b].end())
                ++sum;
        printf("%.2lf%%\n", (sum * 1.0) / (SET[a].size() + SET[b].size() - sum) * 100.0);
    }
    return EXIT_SUCCESS;
}

 这是专门为STL库准备的题啊?…元素数目较多,且不须要顺序排列,选用哈希构造的 unordered_set ! 最后一个测试点耗时仅需92ms。

emmm,这道题的本意应该是考察哈希表,若是语言标准库里没有的话得本身写;端正学习态度后,头铁一波……

自写哈希表,采用平方探测法/装填因子保证在0.33 。

#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
struct SThash
{
    int *hash;
    int hmax, cnt;
};
bool isprime(int num)
{
    if (num < 2)
        return false;
    for (int i = 2; i <= (int)sqrt(num); ++i)
        if (num % i == 0)
            return false;
    return true;
}
int NextPrime(int num)
{
    while (!isprime(num))
        ++num;
    return num;
}
SThash *buildhash(int cnt)
{
    cnt = NextPrime(cnt * 3);
    SThash *T = (SThash *)malloc(sizeof(SThash));
    T->hash = (int *)malloc(cnt * sizeof(int));
    T->hmax = cnt;
    T->cnt = 0;
    memset(T->hash, -1, cnt * sizeof(int));
    return T;
}
void insert(SThash *T, int value)
{
    int temp{value % T->hmax}, base{0};
    while (T->hash[temp] != -1)
    {
        if (T->hash[temp] == value)
            return;
        temp += ((++base) << 1) - 1;
        if (temp >= T->hmax)
            temp -= T->hmax;
    }
    T->hash[temp] = value;
    ++T->cnt;
    return;
}
bool find(SThash *T, int value)
{
    int temp{value % T->hmax}, base{0};
    while (T->hash[temp] != -1 && T->hash[temp] != value)
    {
        temp += ((++base) << 1) - 1;
        if (temp >= T->hmax)
            temp -= T->hmax;
    }
    if (T->hash[temp] == value)
        return true;
    return false;
}
int getdigit(void)
{
    int temp{0};
    char ch;
    while (1)
    {
        ch = getchar();
        if (ch == ' ' || ch == '\n' || ch == EOF)
            return temp;
        temp = temp * 10 + ch - '0';
    }
    return -1;
}
int main(int argc, char *argv[])
{
    int cnt{getdigit()};
    SThash *HashTable[50];
    for (int i = 0; i != cnt; ++i)
    {
        int ind{getdigit()};
        HashTable[i] = buildhash(ind);
        while (ind--)
        {
            int temp{getdigit()};
            insert(HashTable[i], temp);
        }
    }
    cnt = getdigit();
    while (cnt--)
    {
        int a{getdigit()}, b{getdigit()};
        --a, --b;
        int sum{0};
        for (int i = 0; i != HashTable[a]->hmax; ++i)
            if (HashTable[a]->hash[i] != -1 && find(HashTable[b], HashTable[a]->hash[i]))
                ++sum;
        printf("%.2lf%%\n", (sum * 1.0) / (HashTable[a]->cnt + HashTable[b]->cnt - sum) * 100.0);
    }
    return EXIT_SUCCESS;
}

性能和 unordered_set 差很少。

L2-006 树的遍历

#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct node
{
    int left, right;
};
node tree[35];
vector<int> a, b;
int buildtree(int left1, int right1, int left2, int right2)
{
    if (left1 > right1)
        return -1;
    int root{a[right1]}, i;
    for (i = left2; i <= right2; ++i)
        if (root == b[i])
            break;
    int lenl{i - left2 - 1}, lenr{right2 - i - 1};
    --right1;
    tree[root].left = buildtree(left1, left1 + lenl, left2, i - 1);
    tree[root].right = buildtree(right1 - lenr, right1, i + 1, right2);
    return root;
}
void BFS(int root)
{
    queue<int> Q;
    Q.push(root);
    printf("%d", root);
    while (!Q.empty())
    {
        root = Q.front();
        if (tree[root].left != -1)
        {
            Q.push(tree[root].left);
            printf(" %d", tree[root].left);
        }
        if (tree[root].right != -1)
        {
            Q.push(tree[root].right);
            printf(" %d", tree[root].right);
        }
        Q.pop();
    }
    putchar('\n');
    return;
}
int main(int argc, char *argv[])
{
    int cnt;
    scanf("%d", &cnt);
    for (int i = 0; i != cnt; ++i)
    {
        int temp;
        scanf("%d", &temp);
        a.push_back(temp);
    }
    for (int i = 0; i != cnt; ++i)
    {
        int temp;
        scanf("%d", &temp);
        b.push_back(temp);
    }
    BFS(buildtree(0, cnt - 1, 0, cnt - 1));
    return EXIT_SUCCESS;
}

建树;写的并不熟练,须要增强这方面的练习。 

L2-007 家庭房产

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
int unions[10000];
intpair spunions[10000];
struct ans
{
    int index, number;
    double Ecnt, Esum;
};
bool sortcompare(const ans &a, const ans &b)
{
    if (a.Esum == b.Esum)
        return a.index < b.index;
    return a.Esum > b.Esum;
}
int DSUfind(const int &num)
{
    if (unions[num] <= -1)
        return num;
    return unions[num] = DSUfind(unions[num]);
}
void DSUunion(const int &a, const int &b)
{
    int spa{DSUfind(a)}, spb{DSUfind(b)};
    if (spa != spb)
    {
        if (spa < spb)
        {
            unions[spa] += unions[spb];
            spunions[spa].first += spunions[spb].first;
            spunions[spa].second += spunions[spb].second;
            unions[spb] = spa;
        }
        else
        {
            unions[spb] += unions[spa];
            spunions[spb].first += spunions[spa].first;
            spunions[spb].second += spunions[spa].second;
            unions[spa] = spb;
        }
    }
}
int main(int argc, char *argv[])
{
    fill(begin(unions), end(unions), -1);
    int cnt;
    scanf("%d", &cnt);
    while (cnt--)
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        if (b != -1)
            DSUunion(a, b);
        if (c != -1)
            DSUunion(a, c);
        int cntt;
        scanf("%d", &cntt);
        while (cntt--)
        {
            int child;
            scanf("%d", &child);
            DSUunion(a, child);
        }
        scanf("%d%d", &b, &c);
        int temp{DSUfind(a)};
        spunions[temp].first += b;
        spunions[temp].second += c;
    }
    vector<ans> ANS;
    for (int i = 0; i < 10000; ++i)
    {
        if (unions[i] < -1 || (unions[i] == -1 && spunions[i].first))
        {
            ans temp;
            temp.index = i;
            temp.number = -unions[i];
            temp.Ecnt = spunions[i].first / (double)temp.number;
            temp.Esum = spunions[i].second / (double)temp.number;
            ANS.push_back(temp);
        }
    }
    sort(ANS.begin(), ANS.end(), sortcompare);
    printf("%llu\n", ANS.size());
    for (const auto &i : ANS)
        printf("%04d %d %.3lf %.3lf\n", i.index, i.number, i.Ecnt, i.Esum);
    return EXIT_SUCCESS;
}

考察并查集。合并操做的同时注意合并房产套数和总面积,以后再计算平均值,按要求排序后输出。 

 

L2-008 最长对称子串

L2-009 抢红包

L2-010 排座位

L2-011 玩转二叉树

L2-012 关于堆的判断

L2-013 红色警报

L2-014 列车调度

L2-015 互评成绩

L2-016 愿天下有情人都是失散多年的兄妹

L2-017 人以群分

L2-018 多项式A除以B

L2-019 悄悄关注

L2-020 功夫传人

L2-021 点赞狂魔

L2-022 重排链表

L2-023 图着色问题

L2-024 部落

L2-025 分而治之

L2-026 小字辈

L2-027 名人堂与代金券

L2-028 秀恩爱分得快

 

END