#P3061. VLAN资源池(100分)
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 130
            Accepted: 48
            Difficulty: 3
            
          
          
          
                       所属公司 : 
                              华为od
                                
            
                      
          
 
- 
                        算法标签>模拟          
 
VLAN资源池(100分)
题面描述
VLAN(虚拟局域网)是一种对局域网设备进行逻辑划分的技术。为了标识不同的VLAN,引入了VLAN ID(取值范围为1-4094)的概念。
定义一个VLAN ID的资源池(以下简称VLAN资源池),资源池中连续的VLAN用“开始VLAN-结束VLAN”表示,不连续的用单个整数表示,所有的VLAN用英文逗号连接起来。
现在有一个VLAN资源池,业务需要从资源池中申请一个VLAN,需要你输出从VLAN资源池中移除申请的VLAN后的资源池。
思路
- 
解析输入的VLAN资源池字符串:
- 使用逗号分割字符串,得到各个VLAN段。
 - 对于每个段,判断是否为范围(含有“-”),如果是,则将范围内的所有VLAN加入集合;否则,将单个VLAN加入集合。
 
 - 
移除申请的VLAN:
- 检查申请的VLAN是否在集合中,如果在,则移除;否则,保持集合不变。
 
 - 
排序VLAN集合:
- 将集合中的VLAN按照升序排序。
 
 - 
重新格式化VLAN资源池字符串:
- 遍历排序后的VLAN集合,合并连续的VLAN为范围表示。
 - 将结果用逗号连接成最终的字符串输出。
 
 - 
注意事项:
- 输入的VLAN资源池可能是乱序的,需先解析成集合并排序。
 - 移除后的VLAN集合可能会分成多个连续段,需要正确合并。
 
 
代码分析
- 
函数
split:- 用于将输入字符串按指定分隔符(逗号)拆分成多个子串。
 
 - 
函数
parseVLANPool:- 接受一个字符串形式的VLAN资源池,解析并返回一个包含所有VLAN的
set<int>集合。 - 对于每个子串,如果包含“-”,则解析为范围并加入集合;否则,直接加入单个VLAN。
 
 - 接受一个字符串形式的VLAN资源池,解析并返回一个包含所有VLAN的
 - 
函数
formatVLANPool:- 接受一个排序后的
vector<int>集合,将其格式化为题目要求的字符串形式。 - 遍历VLAN集合,合并连续的VLAN为范围,单独的VLAN保持单个表示。
 
 - 接受一个排序后的
 - 
主函数
main:- 读取输入的VLAN资源池字符串和要申请的VLAN。
 - 调用
parseVLANPool解析资源池。 - 移除申请的VLAN(如果存在)。
- 使用
set的erase方法进行移除。 
 - 使用
 - 将剩余的VLAN集合转换为排序后的
vector<int>。 - 调用
formatVLANPool格式化输出字符串。 - 输出结果。
 
 
cpp
#include <bits/stdc++.h>
using namespace std;
// 函数:将字符串按照指定分隔符分割
vector<string> split(const string &s, char delimiter) {
    vector<string> tokens;
    string token;
    // 使用stringstream进行分割
    stringstream ss(s);
    while (getline(ss, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}
// 函数:解析VLAN资源池字符串,返回一个包含所有VLAN的集合
set<int> parseVLANPool(const string &s) {
    set<int> vlanSet;
    vector<string> segments = split(s, ',');
    for (const string &seg : segments) {
        // 检查是否为范围
        size_t dashPos = seg.find('-');
        if (dashPos != string::npos) {
            // 是范围,提取开始和结束
            string startStr = seg.substr(0, dashPos);
            string endStr = seg.substr(dashPos + 1);
            // 转换为整数
            int start = stoi(startStr);
            int end = stoi(endStr);
            // 确保start <= end
            if (start > end) swap(start, end);
            // 添加范围内所有VLAN
            for (int i = start; i <= end; ++i) {
                vlanSet.insert(i);
            }
        }
        else {
            // 是单个VLAN
            int vlan = stoi(seg);
            vlanSet.insert(vlan);
        }
    }
    return vlanSet;
}
// 函数:将排序后的VLAN列表格式化为题目要求的字符串
string formatVLANPool(const vector<int> &vlans) {
    if (vlans.empty()) return "";
    string result;
    int n = vlans.size();
    int start = vlans[0];
    int prev = vlans[0];
    for (int i = 1; i < n; ++i) {
        if (vlans[i] == prev + 1) {
            // 连续
            prev = vlans[i];
        }
        else {
            // 不连续,记录前面的范围
            if (start == prev) {
                result += to_string(start) + ",";
            }
            else {
                result += to_string(start) + "-" + to_string(prev) + ",";
            }
            // 更新start和prev
            start = vlans[i];
            prev = vlans[i];
        }
    }
    // 处理最后一个范围
    if (start == prev) {
        result += to_string(start);
    }
    else {
        result += to_string(start) + "-" + to_string(prev);
    }
    return result;
}
int main(){
    string vlanPoolStr;
    string applyVLANStr;
    // 读取输入
    getline(cin, vlanPoolStr);
    getline(cin, applyVLANStr);
    // 解析VLAN资源池
    set<int> vlanSet = parseVLANPool(vlanPoolStr);
    // 解析要申请的VLAN
    int applyVLAN = stoi(applyVLANStr);
    // 移除申请的VLAN
    vlanSet.erase(applyVLAN);
    // 将集合转换为排序的向量
    vector<int> vlanList(vlanSet.begin(), vlanSet.end());
    sort(vlanList.begin(), vlanList.end());
    // 格式化输出
    string output = formatVLANPool(vlanList);
    cout << output;
    return 0;
}
python
def split(s, delimiter):
    """将字符串按照指定分隔符分割"""
    return s.split(delimiter)
def parse_vlan_pool(s):
    """解析 VLAN 资源池字符串,返回一个包含所有 VLAN 的集合"""
    vlan_set = set()
    segments = split(s, ',')
    
    for seg in segments:
        # 检查是否为范围
        if '-' in seg:
            start_str, end_str = seg.split('-')
            start = int(start_str)
            end = int(end_str)
            # 确保 start <= end
            if start > end:
                start, end = end, start
            # 添加范围内所有 VLAN
            for i in range(start, end + 1):
                vlan_set.add(i)
        else:
            # 是单个 VLAN
            vlan_set.add(int(seg))
    
    return vlan_set
def format_vlan_pool(vlans):
    """将排序后的 VLAN 列表格式化为题目要求的字符串"""
    if not vlans:
        return ""
    
    result = []
    sorted_vlans = sorted(vlans)
    start = sorted_vlans[0]
    prev = sorted_vlans[0]
    for vlan in sorted_vlans[1:]:
        if vlan == prev + 1:
            # 连续
            prev = vlan
        else:
            # 不连续,记录前面的范围
            if start == prev:
                result.append(str(start))
            else:
                result.append(f"{start}-{prev}")
            # 更新 start 和 prev
            start = vlan
            prev = vlan
    # 处理最后一个范围
    if start == prev:
        result.append(str(start))
    else:
        result.append(f"{start}-{prev}")
    
    return ",".join(result)
def main():
    # 读取输入
    vlan_pool_str = input().strip()
    apply_vlan_str = input().strip()
    
    # 解析 VLAN 资源池
    vlan_set = parse_vlan_pool(vlan_pool_str)
    # 解析要申请的 VLAN
    apply_vlan = int(apply_vlan_str)
    
    # 移除申请的 VLAN
    vlan_set.discard(apply_vlan)
    
    # 格式化输出
    output = format_vlan_pool(vlan_set)
    print(output)
if __name__ == "__main__":
    main()
java
import java.util.*;
public class VLANManager {
    // 函数:将字符串按照指定分隔符分割
    public static List<String> split(String s, char delimiter) {
        return Arrays.asList(s.split(String.valueOf(delimiter)));
    }
    // 函数:解析 VLAN 资源池字符串,返回一个包含所有 VLAN 的集合
    public static Set<Integer> parseVLANPool(String s) {
        Set<Integer> vlanSet = new HashSet<>();
        List<String> segments = split(s, ',');
        
        for (String seg : segments) {
            // 检查是否为范围
            if (seg.contains("-")) {
                String[] bounds = seg.split("-");
                int start = Integer.parseInt(bounds[0]);
                int end = Integer.parseInt(bounds[1]);
                // 确保 start <= end
                if (start > end) {
                    int temp = start;
                    start = end;
                    end = temp;
                }
                // 添加范围内所有 VLAN
                for (int i = start; i <= end; i++) {
                    vlanSet.add(i);
                }
            } else {
                // 是单个 VLAN
                vlanSet.add(Integer.parseInt(seg));
            }
        }
        
        return vlanSet;
    }
    // 函数:将排序后的 VLAN 列表格式化为题目要求的字符串
    public static String formatVLANPool(List<Integer> vlans) {
        if (vlans.isEmpty()) {
            return "";
        }
        StringBuilder result = new StringBuilder();
        Collections.sort(vlans);
        int start = vlans.get(0);
        int prev = vlans.get(0);
        
        for (int i = 1; i < vlans.size(); i++) {
            int vlan = vlans.get(i);
            if (vlan == prev + 1) {
                // 连续
                prev = vlan;
            } else {
                // 不连续,记录前面的范围
                if (start == prev) {
                    result.append(start).append(",");
                } else {
                    result.append(start).append("-").append(prev).append(",");
                }
                // 更新 start 和 prev
                start = vlan;
                prev = vlan;
            }
        }
        // 处理最后一个范围
        if (start == prev) {
            result.append(start);
        } else {
            result.append(start).append("-").append(prev);
        }
        return result.toString();
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 读取输入
        String vlanPoolStr = scanner.nextLine().trim();
        String applyVLANStr = scanner.nextLine().trim();
        
        // 解析 VLAN 资源池
        Set<Integer> vlanSet = parseVLANPool(vlanPoolStr);
        // 解析要申请的 VLAN
        int applyVLAN = Integer.parseInt(applyVLANStr);
        
        // 移除申请的 VLAN
        vlanSet.remove(applyVLAN);
        
        // 将集合转换为排序的列表
        List<Integer> vlanList = new ArrayList<>(vlanSet);
        
        // 格式化输出
        String output = formatVLANPool(vlanList);
        System.out.println(output);
        
        scanner.close();
    }
}
        题目内容
VLAN是一种对局域网设备进行逻辑划分的技术,为了标识不同的VLAN,引入VLAN ID(1−4094)之间的整数)的概念。
定义一个VLAN ID的资源池(下称VLAN资源池),资源池中连续的VLAN用开始VLAN−结束VLAN表示,不连续的用单个整数表示,所有的VLAN用英文逗号连接起来。
现在有一个VLAN资源池,业务需要从资源池中申请一个VLAN,需要你输出从VLAN资源池中移除申请的VLAN后的资源池。
输入描述
第一行为字符串格式的VLAN资源池,第二行为业务要申请的VLAN,VLAN的取值范围为[1,4094]之间的整数。
输出描述
从输入VLAN资源池中移除申请的VLAN后字符串格式的VLAN资源池,输出要求满足题目描述中的格式,并且按照VLAN从小到大升序输出。
如果申请的VLAN不在原VLAN资源池内,输出原VLAN资源池升序排序后的字符串即可。
备注
输入VLAN资源池中VLAN的数量取值范围为[2−4094]间的整数,资源池中VLAN不重复且合法([1,4094]之间的整数),输入是乱序的。
示例1
输入
1-5
2
输出
1,3-5
说明
原VLAN资源池中有VLAN 1、2、3、4、5,从资源池中移除2后,剩下VLAN 1、3、4、5,按照题目描述格式并升序后的结果为1,3-5。
示例2
输入
20-21,15,18,30,5-10
15
输出
5-10,18,20-21,30
说明
原VLAN资源池中有VLAN 5、6、7、8、9、10、15、18、20、21、30,从资源池中移除15后,资源池中剩下的VLAN为 5、6、7、8、9、10、18、20、21、30,按照题目描述格式并升序后的结果为5-10,18,20-21,30。
示例3
输入
5,1-3
10
输出
1-3,5
说明
原VLAN资源池中有VLAN 1、2、3,5,申请的VLAN 10不在原资源池中,将原资源池按照题目描述格式并按升序排序后输出的结果为1-3,5。