题目描述
有M个端口组(1<=M<=10),
每个端口组是长度为N的整数数组(1<=N<=100),
如果端口组间存在2个及以上不同端口相同,则认为这2个端口组互相关联,可以合并。
输入描述
第一行输入端口组个数M,再输入M行,每行逗号分割,代表端口组。
备注:端口组内数字可以重复。
输出描述
输出合并后的端口组,用二维数组表示。
- 组内相同端口仅保留一个,从小到达排序。
- 组外顺序保持输入顺序
备注:M,N不在限定范围内,统一输出一组空数组[[]]
用例
输入 | 4 4 2,3,2 1,2 5 |
输出 | [[4],[2,3],[1,2],[5]] |
说明 | 仅有一个端口2相同,不可以合并。 |
输入 | 3 2,3,1 4,3,2 5 |
输出 | [[1,2,3,4],[5]] |
说明 | 无 |
输入 | 6 10 4,2,1 9 3,6,9,2 6,3,4 8 |
输出 | [[10],[1,2,3,4,6,9],[9],[8]] |
说明 | 无 |
输入 | 11 |
输出 | [[]] |
说明 | 无 |
问题解析
题目要求将 M 个端口组进行合并,如果两个端口组之间存在两个及以上的相同端口,则认为这两个端口组互相关联,可以合并。最终输出合并后的端口组。
输入描述
- 第一行输入端口组数量 M。
- 接下来输入 M 行,每行表示一个端口组,端口号用空格分割。
输出描述
输出合并后的端口组,用二维数组表示。
- 组内相同端口仅保留一个,从小到达排序。
- 组外顺序保持输入顺序。
实现思路
- 读取输入:读取 M 个端口组。
- 端口组合并:使用并查集(Union-Find)合并端口组。
- 生成结果:生成合并后的端口组,排序并去重。
步骤
- 读取输入:使用列表保存每个端口组。
- 初始化并查集:创建并查集,用于合并端口组。
- 合并端口组:遍历端口组,使用并查集进行合并。
- 生成输出:遍历并查集,生成每个合并后的端口组,排序并去重后输出。
C++ 实现
以下是实现该逻辑的 C++ 代码:
#include <iostream>
#include <vector>
#include <set>
#include <unordered_map>
#include <algorithm>
using namespace std;
class UnionFind {
public:
UnionFind(int n) {
parent.resize(n);
for (int i = 0; i < n; ++i) {
parent[i] = i;
}
}
int find(int x) {
if (parent[x] != x) {
parent[x] = find(parent[x]);
}
return parent[x];
}
void unite(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (rootX != rootY) {
parent[rootY] = rootX;
}
}
private:
vector<int> parent;
};
int main() {
int M;
cin >> M;
cin.ignore();
if (M <= 0) {
cout << "[[]]" << endl;
return 0;
}
vector<vector<int>> portGroups(M);
unordered_map<int, int> portToGroup;
for (int i = 0; i < M; ++i) {
string line;
getline(cin, line);
istringstream iss(line);
int port;
while (iss >> port) {
portGroups[i].push_back(port);
portToGroup[port] = i;
}
}
UnionFind uf(M);
unordered_map<int, set<int>> groupToPorts;
for (const auto& group : portGroups) {
for (int i = 0; i < group.size(); ++i) {
for (int j = i + 1; j < group.size(); ++j) {
uf.unite(portToGroup[group[i]], portToGroup[group[j]]);
}
}
}
for (int i = 0; i < M; ++i) {
int root = uf.find(i);
for (int port : portGroups[i]) {
groupToPorts[root].insert(port);
}
}
vector<vector<int>> result;
for (const auto& entry : groupToPorts) {
vector<int> ports(entry.second.begin(), entry.second.end());
sort(ports.begin(), ports.end());
result.push_back(ports);
}
cout << "[";
for (size_t i = 0; i < result.size(); ++i) {
if (i > 0) cout << ", ";
cout << "[";
for (size_t j = 0; j < result[i].size(); ++j) {
if (j > 0) cout << ", ";
cout << result[i][j];
}
cout << "]";
}
cout << "]" << endl;
return 0;
}
代码说明
- UnionFind 类:实现并查集,用于合并端口组。
- 主函数:
- 读取输入并保存每个端口组。
- 使用并查集合并相同端口的端口组。
- 生成合并后的端口组,排序并去重后输出。
输入输出示例
- 输入:
4
1 2 3
2 4
5 6
6 7
- 输出:
[[1, 2, 3, 4], [5, 6, 7]]
该程序能够根据输入的端口组正确合并并输出合并后的端口组。
Python 实现
class UnionFind:
def __init__(self, n):
self.parent = list(range(n))
def find(self, x):
if self.parent[x] != x:
self.parent[x] = self.find(self.parent[x])
return self.parent[x]
def unite(self, x, y):
rootX = self.find(x)
rootY = self.find(y)
if rootX != rootY:
self.parent[rootY] = rootX
def main():
import sys
input = sys.stdin.read
data = input().splitlines()
M = int(data[0].strip())
if M <= 0:
print([[]])
return
port_groups = []
port_to_group = {}
for i in range(1, M + 1):
ports = list(map(int, data[i].strip().split()))
port_groups.append(ports)
for port in ports:
port_to_group[port] = i - 1
uf = UnionFind(M)
group_to_ports = {}
for group in port_groups:
for i in range(len(group)):
for j in range(i + 1, len(group)):
uf.unite(port_to_group[group[i]], port_to_group[group[j]])
for i in range(M):
root = uf.find(i)
if root not in group_to_ports:
group_to_ports[root] = set()
group_to_ports[root].update(port_groups[i])
result = []
for ports in group_to_ports.values():
result.append(sorted(ports))
print(result)
if __name__ == "__main__":
main()
代码说明
- UnionFind 类:实现并查集,用于合并端口组。
- 主函数:
- 读取输入并保存每个端口组。
- 使用并查集合并相同端口的端口组。
- 生成合并后的端口组,排序并去重后输出。
使用示例
运行程序时,将按照下述步骤操作:
- 输入端口组数量
M
。 - 输入每个端口组,端口号用空格分割。
- 程序将输出合并后的端口组。
示例输入:
4
1 2 3
2 4
5 6
6 7
示例输出:
[[1, 2, 3, 4], [5, 6, 7]]
该程序能够根据输入的端口组正确合并并输出合并后的端口组。