复赛三:网络链接(network)

洛谷:P7911
OJ: 4972

不判断ip合法性,能得55分。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <map>
using namespace std;
int n;
map<string,int> server;

//判断 ip合法性
bool check(string ip){
    return true;
}
int main(){
    cin>>n;
    string s,t;
    for (int i = 1; i <=n; i++){
        cin>>s>>t;
        if(!check(t)){
            cout<<"ERR"<<endl;
            continue;
        }
        if(s=="Server"){
           if(server[t]==0){
            server[t]=i;
            cout<<"OK"<<endl;
           }else{
            cout<<"FAIL"<<endl;
        }
    }else{
        if(server[t]>0){
            cout<<server[t]<<endl;
        }else{
            cout<<"FAIL"<<endl;
        }
    }
}
}

满分方法一:代码详细解读:

  1. 变量定义部分
    • n:表示要处理的计算机的数量。
    • server:一个 map,用于存储成功建立连接的服务机地址与其编号的映射关系。
  2. check 函数:用于验证地址串是否符合 IP 地址的规范格式。
    • 解析地址串,统计 .: 出现的次数,同时提取 IP 地址中的 a,b,c,d 及端口号 e。
    • 检查各个数字的合法性,确保它们在正确范围内且没有前导零。
    • 如果所有检查通过,返回 true,否则返回 false
  3. 主程序
    • 读取输入的操作类型(Server 或 Client)及地址串。
    • 调用 check 函数检查地址串是否合法:
      • 如果地址不合法,输出 “ERR” 并跳过该操作。
      • 如果是服务机,检查该地址是否已被其他服务机使用:
        • 如果未被使用,记录该服务机的地址,输出 “OK” 表示成功建立连接。
        • 如果已被使用,输出 “FAIL” 表示建立连接失败。
      • 如果是客户机,检查是否有服务机使用该地址:
        • 如果找到匹配的服务机,输出该服务机的编号。
        • 如果未找到,输出 “FAIL”。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
/**************************************************************** 
 * Description: 2021年普及组复赛第三题  网络连接
 * Author: Alex Li
 * Date: 2023-10-16 10:33:25
 * LastEditTime: 2024-10-18 11:22:47
****************************************************************/
#include <iostream>
#include <map>
using namespace std;

int n;  // 代表计算机的总数
map<string, int> server;  // 用于记录服务机已成功建立连接的地址及其编号

// 判断 IP 地址是否符合规范的函数
bool check(string s) {
    int len = s.length();  // 获取地址字符串的长度
    long long tmp = 0;  // 临时变量,用于提取数字
    int cnt1 = 0, cnt2 = 0, cnt3 = 0;  // cnt1 统计 '.' 的个数,cnt2 统计 ':' 的个数,cnt3 统计数字的个数

    for (int i = 0; i < len; i++) {
        // 如果当前位置为第一个字符或前一个字符为 '.' 或 ':' 且当前位置是数字,则增加数字计数器
        if ((i == 0 || (s[i-1] == '.' || s[i-1] == ':')) && s[i] >= '0' && s[i] <= '9') 
            cnt3++;

        // 如果当前位置是 '.' 或 ':' 
        if (s[i] == '.' || s[i] == ':') {
            if (s[i] == '.') 
                cnt1++;  // '.' 出现,增加计数器
            else if (s[i] == ':') 
                cnt2++;  // ':' 出现,增加计数器

            // 检查 '.' 和 ':' 出现的顺序是否符合规范
            if (cnt1 < 3 && cnt2 > 0) return false;  // 如果 ':' 出现在第三个 '.' 之前,不符合规范
            if (cnt3 == 0) return false;  // 如果 '.' 或 ':' 出现在没有数字的情况下,不符合规范
            
            // 检查数字部分 a,b,c,d 是否在合法范围内
            if (0 <= tmp && tmp <= 255) {
                tmp = 0;  // 数字合法,重置 tmp 继续处理下一个数字
                continue;
            } else {
                return false;  // 数字不合法,返回 false
            }
        }
        // 如果出现了非数字字符,返回 false
        else if (s[i] < '0' || s[i] > '9') 
            return false;

        // 检查是否有前导 0(前导 0 在 IP 地址中是不允许的)
        if (i > 0 && !tmp && s[i-1] == '0') 
            return false;

        // 提取当前数字并存入 tmp
        tmp = tmp * 10 + s[i] - '0';
    }

    // 检查 '.' 出现的次数是否为 3,':' 出现的次数是否为 1,以及数字部分是否有 5 个
    if (cnt1 != 3 || cnt2 != 1 || cnt3 != 5) 
        return false;

    // 检查端口号(e)是否在合法范围内(0 到 65535)
    if (0 <= tmp && tmp <= 65535) 
        return true;
    else 
        return false;
}

int main() {
    cin >> n;  // 读取计算机数量
    string s, t;  // s 用于存储操作类型(Server 或 Client),t 用于存储地址串

    for (int i = 1; i <= n; i++) {
        cin >> s >> t;  // 读取每台计算机的操作类型和地址串

        // 检查地址串是否合法
        if (!check(t)) {
            cout << "ERR" << endl;  // 如果地址不合法,输出 "ERR"
            continue;  // 继续处理下一台计算机
        }

        // 如果是服务机
        if (s == "Server") {
            // 检查该地址是否已经有其他服务机使用
            if (server[t] == 0) {
                // 如果该地址未被使用,成功建立连接并记录
                server[t] = i;
                cout << "OK" << endl;  // 输出 "OK" 表示成功建立连接
            } else {
                // 如果地址已被使用,输出 "FAIL"
                cout << "FAIL" << endl;
            }
        } else {  // 如果是客户机
            // 检查是否有服务机使用该地址
            if (server[t] > 0) {
                // 如果找到匹配的服务机,输出该服务机的编号
                cout << server[t] << endl;
            } else {
                // 如果未找到匹配的服务机,输出 "FAIL"
                cout << "FAIL" << endl;
            }
        }
    }
}

满分方法二:调用了sscanf和sprintf

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <map>
#include <stdio.h>
using namespace std;
int n;
map<string,int> server;

//判断 ip合法性
bool check(string ip){
    int t[6]={0,-1,-1,-1,-1,-1};
    int cnt=sscanf(ip.c_str(),"%d.%d.%d.%d:%d",&t[1],&t[2],&t[3],&t[4],&t[5]);
    if(cnt!=5)return false;
    for (int i =1; i <=4; i++){
        if(t[i]<0||t[i]>255)return false;
    }
    if(t[5]<0||t[5]>65535)return false;
    char now[30];
    sprintf(now,"%d.%d.%d.%d:%d",t[1],t[2],t[3],t[4],t[5]);
    if(string(now)!=ip) return false;
    return true;
}

int main(){
    cin>>n;
    string s,t;
    for (int i = 1; i <=n; i++){
        cin>>s>>t;
        if(!check(t)){
            cout<<"ERR"<<endl;
            continue;
        }
        if(s=="Server"){
           if(server[t]==0){
            server[t]=i;
            cout<<"OK"<<endl;
           }else{
            cout<<"FAIL"<<endl;
        }
    }else{
        if(server[t]>0){
            cout<<server[t]<<endl;
        }else{
            cout<<"FAIL"<<endl;
        }
    }
}
}

Scroll to Top