TB椰程 TypeBuddy 打字搭子

2021 网络连接 · 方案一 手写解析

CSP-J 标程 · 复赛真题 · 代码 · cpp · 难度 3/5 · 共 2124 字

逐段检查数字、前导零与取值范围

  • 2021
  • 字符串

正文

// CSP-J 2021 复赛 T3 · 网络连接
// 原题:https://oj.yecheng.tv/p/CSPJ2021C
// 题意:判断地址串是不是合法的 a.b.c.d:e(五个数都非负整数、无多余前导零、
// a~d 不超过 255、e 不超过 65535)。服务机用过的地址不能重复建立;
// 客户机要连上之前建好的、地址完全相同的服务机。
// 输出:地址不合法一律 ERR;服务机重名 FAIL、成功 OK;客户机找不到 FAIL、找到就输出服务机编号。
//
// 方案一 · 手写解析(最严谨,一步一步把串拆开)
// 先按分隔符切成 5 段,同时检查分隔符的形状必须是「点 点 点 冒号」;
// 再逐段检查:只能有数字、长度不能为 0、有多余前导零不行、数值不能超上限。
// 之后用一个 map 把「地址串 -> 建好它的服务机编号」记下来即可。

#include <bits/stdc++.h>
using namespace std;

bool validPart(const string& t, int limit) {
    if (t.empty()) return false;
    if (t.size() > 1 && t[0] == '0') return false;      // 多余前导零
    long long x = 0;
    for (char c : t) {
        if (!isdigit((unsigned char)c)) return false;
        x = x * 10 + (c - '0');
        if (x > limit) return false;                    // 边读边判,不会溢出
    }
    return true;
}

bool check(const string& s) {
    string part[5];
    int idx = 0;
    string cur;
    for (size_t i = 0; i < s.size(); i++) {
        char c = s[i];
        if (c == '.') {
            if (idx >= 3) return false;                 // 点只出现在前三段后面
            part[idx++] = cur;
            cur.clear();
        } else if (c == ':') {
            if (idx != 3) return false;                 // 冒号只能跟在第四段后面
            part[idx++] = cur;
            cur.clear();
        } else {
            cur += c;
        }
    }
    if (idx != 4) return false;
    part[4] = cur;
    for (int i = 0; i < 4; i++) {
        if (!validPart(part[i], 255)) return false;
    }
    return validPart(part[4], 65535);
}

int main() {
    freopen("network.in", "r", stdin);
    freopen("network.out", "w", stdout);

    int n;
    cin >> n;
    map<string, int> server;
    for (int i = 1; i <= n; i++) {
        string op, ad;
        cin >> op >> ad;
        if (!check(ad)) {
            cout << "ERR\n";
        } else if (op == "Server") {
            if (server.count(ad)) cout << "FAIL\n";
            else {
                server[ad] = i;
                cout << "OK\n";
            }
        } else {
            if (server.count(ad)) cout << server[ad] << "\n";
            else cout << "FAIL\n";
        }
    }
    return 0;
}

CSP-J 标程 · 复赛真题的其它内容

打字首页 · 词库画廊 · 编程打字 · 指法入门 · 天梯榜 · 数据分析 · 班级课堂 · 关于我们
椰程 TypeBuddy 打字搭子 —— 键盘指法练习 · 单词记忆 · 班级课堂 · 在线 PK