网络连接
按顺序处理 n 台机器的操作,每台机器分为服务机(Server)或客户机(Client),并附带一个地址串。需要先校验地址串是否符合 a.b.c.d:e 格式(数值不超界且无前导零),若非法输出 ERR;若合法,服务机需在未被占用时建立连接(成功输出 OK,重复输出 FAIL),客户机则尝试连接已建立的服务机(成功输出对应服务机编号,无匹配输出 FAIL)。
CSP-J2分钟阅读

这是一道大模拟与字符串解析题,由于数据规模较小(),算法的重点在于精准判断字符串格式是否合法,以及使用高效的数据结构进行服务机地址的匹配。
对于输入的每一行命令,处理分为两步:
-
- 先校验地址串是否满足标准的
a.b.c.d:e格式。 - 检查数值范围:,且 。
- 检查前导零:除了数字本身为
0的情况外,不能包含前导零(例如01是不合法的)。 - 若不合法,直接输出
ERR。
- 先校验地址串是否满足标准的
-
如果操作是
Server:- 查询该地址串是否已被成功建立过的服务机占用。
- 若已占用,输出
FAIL。 - 若未占用,记录该地址串与当前机器编号 的映射关系,并输出
OK。
如果操作是
Client:- 查询该地址串是否有服务机在监听。
- 若有,输出该服务机的编号 。
- 若无,输出
FAIL。
可以通过 sscanf 函数结合格式格式化校验,或者手动校验。利用 C++ 的 sscanf 可以非常简洁地解析,但为了防止非法字符绕过,还需要校验重新拼接后的字符串与原字符串是否完全一致。
sscanf 技巧:
利用 sscanf(s.c_str(), "%lld.%lld.%lld.%lld:%lld", &a, &b, &c, &d, &e) 提取 5 个数字。
为了验证格式(是否有多余字符、多余前导零、超出范围),可以将提取出的 a, b, c, d, e 用 sprintf 或 to_string 重新按 a.b.c.d:e 格式拼回字符串 t。
- 如果
s == t且数值范围均合法,则原字符串必定完全合法!这种方法能完美规避绝大多数格式陷阱(如前导零、多余的符号等)。
- 因为需要根据合法地址串快速查找对应的服务机编号,使用 C++ STL 中的
map<string, int>即可。 - 插入和查找的时间复杂度为 ,总时间复杂度为 ,在 下可以轻松通过(运行时间远小于 1.00s)。
#include <iostream>#include <string>#include <map>#include <cstdio>
using namespace std;
// 检查地址串是否合法bool check(const string& s) { long long a, b, c, d, e;
// 尝试按照指定格式解析出 5 个整数 int ret = sscanf(s.c_str(), "%lld.%lld.%lld.%lld:%lld", &a, &b, &c, &d, &e);
// 如果解析出的整数个数不等于 5 个,说明格式错误 if (ret != 5) return false;
// 检查范围是否合法 if (a < 0 || a > 255) return false; if (b < 0 || b > 255) return false; if (c < 0 || c > 255) return false; if (d < 0 || d > 255) return false; if (e < 0 || e > 65535) return false;
// 重新按格式拼接,验证是否有前导零或多余字符 char buf[100]; sprintf(buf, "%lld.%lld.%lld.%lld:%lld", a, b, c, d, e);
// 原字符串与重新格式化的字符串必须完全一致 return s == string(buf);}
int main() { // 优化标准输入输出速度 ios::sync_with_stdio(false); cin.tie(nullptr);
int n; if (!(cin >> n)) return 0;
map<string, int> server_map; // 保存合法服务机的 <地址串, 编号>
for (int i = 1; i <= n; ++i) { string op, ad; cin >> op >> ad;
// 1. 检查地址规范 if (!check(ad)) { cout << "ERR\n"; continue; }
// 2. 根据操作类型进行处理 if (op == "Server") { if (server_map.count(ad)) { cout << "FAIL\n"; // 地址已经被其他服务机占用 } else { server_map[ad] = i; // 记录服务机编号 cout << "OK\n"; } } else if (op == "Client") { if (server_map.count(ad)) { cout << server_map[ad] << "\n"; // 连接成功,输出服务机编号 } else { cout << "FAIL\n"; // 找不到可连接的服务机 } } }
return 0;}- 时间复杂度: ,其中 为字符串最大长度。每次
check耗时 ,map查找/插入耗时 。总运算量不超过 次操作,运行时间在 0.05 秒以内。 - 空间复杂度: ,主要用于
map存储建立成功的服务机地址信息。内存开销极小。