题目描述
现有一个 VLAN 资源池,描述格式为逗号分隔的若干段:连续的 VLAN 用 起始ID-结束ID 表示,单个 VLAN 直接写 ID。业务申请一个 VLAN:若池中存在,则将其移除并输出剩余资源池;若不存在,则原样输出资源池。
输出格式要求: 按升序排列,连续 ID 合并为 a-b,单个 ID 单独输出,逗号分隔。
示例
输入:
1-5,8,10-14
4
输出:
1-3,5,8,10-14
输入:
20-21,5,8,10-14
10
输出:
5,8,11-14,20-21
思路
- VLAN 范围只有 1~4094,直接开一个标记数组,把每段区间打上标记;
- 将申请的 VLAN 标记清零(不存在则相当于没变);
- 从小到大扫描,找连续段输出即可,天然完成排序与合并。
C 代码
#include <stdio.h>
#include <string.h>
#define N 4096 /* VLAN ID 取值范围 1~4094 */
int inPool[N]; /* inPool[i]=1 表示 VLAN i 在池中 */
int main(void)
{
char line[10005];
int need;
if (fgets(line, sizeof(line), stdin) == NULL) return 0;
line[strcspn(line, "\r\n")] = '\0'; /* 去掉行尾换行符 */
scanf("%d", &need);
/* 1. 按逗号切分,解析每一段并打标记 */
char *tok = strtok(line, ",");
while (tok != NULL) {
int a = 0, b = 0;
if (sscanf(tok, "%d-%d", &a, &b) == 2) { /* 形如 a-b */
for (int i = a; i <= b && i < N; i++) inPool[i] = 1;
} else { /* 单个数字 */
sscanf(tok, "%d", &a);
if (a >= 0 && a < N) inPool[a] = 1;
}
tok = strtok(NULL, ",");
}
/* 2. 移除申请的 VLAN(不在池中则等于没变) */
if (need >= 0 && need < N) inPool[need] = 0;
/* 3. 从小到大扫描,输出连续段 */
int first = 1;
for (int i = 1; i < N; i++) {
if (!inPool[i]) continue;
int j = i;
while (j + 1 < N && inPool[j + 1]) j++; /* 找连续段终点 */
if (!first) putchar(',');
if (i == j) printf("%d", i); /* 单个 ID */
else printf("%d-%d", i, j); /* 连续区间 */
first = 0;
i = j; /* 跳过整段 */
}
putchar('\n');
return 0;
}