试题 J: 网络分析
时间限制: 1.0s 内存限制: 512.0MB 本题总分:25 分
【问题描述】
小明正在做一个网络实验。
他设置了 n 台电脑,称为节点,用于收发和存储数据。
初始时,所有节点都是独立的,不存在任何连接。
小明可以通过网线将两个节点连接起来,连接后两个节点就可以互相通信
了。两个节点如果存在网线连接,称为相邻。
小明有时会测试当时的网络,他会在某个节点发送一条信息,信息会发送
到每个相邻的节点,之后这些节点又会转发到自己相邻的节点,直到所有直接
或间接相邻的节点都收到了信息。所有发送和接收的节点都会将信息存储下来。
一条信息只存储一次。
给出小明连接和测试的过程,请计算出每个节点存储信息的大小。
【输入格式】
输入的第一行包含两个整数 n,m,分别表示节点数量和操作数量。节点从
1 至 n 编号。
接下来 m 行,每行三个整数,表示一个操作。
如果操作为 1 a b,表示将节点 a 和节点 b 通过网线连接起来。当 a = b
时,表示连接了一个自环,对网络没有实质影响。
如果操作为 2 p t,表示在节点 p 上发送一条大小为 t 的信息。
【输出格式】
输出一行,包含 n 个整数,相邻整数之间用一个空格分割,依次表示进行
完上述操作后节点 1 至节点 n 上存储信息的大小。【样例输入】
4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1
【样例输出】
13 13 5 3
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ n ≤ 20,1 ≤ m ≤ 100。
对于 50% 的评测用例,1 ≤ n ≤ 100,1 ≤ m ≤ 1000。
对于 70% 的评测用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 10000。
对于所有评测用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000,1 ≤ t ≤ 100。
代码:
class T10 {
public T10() {
Scanner sn = new Scanner(System.in);
int n = sn.nextInt();// 节点数量
int m = sn.nextInt();// 操作数量
//存放网络节点
List<Node> list = new ArrayList<Node>();
//节点 映射 网络(这里用set集合相当于网络)
Map<Node,HashSet<Node>> map=new HashMap<Node,HashSet<Node>>();
for (int i = 0; i < n; i++) {
Node node=new Node(i);
node.nodelist.add(node);//把自己加入自己的网络
map.put(node,node.nodelist);//将节点与自己的网络进行映射
list.add(node);//将节点加入列表
}
for (int i = 0; i < m; i++) {
int a = sn.nextInt();
int b = sn.nextInt();
int c = sn.nextInt();
//操作1,两个节点连接,相当于合并网络,这里将第二个节点合并入第一个
if (a == 1) {
if (b >= 1 && c >= 1 && b != c) {
Node nb=list.get(b-1);
Node nc=list.get(c-1);
//若nb的网络已经存在nc,则不需要合并
if(map.get(nb).contains(nc)) {
continue;
}
/**先将nc加入nb的网络,
**然后再讲nc的网络节点转移到nb
**然后清空nc的网络
**将nc指向nb的网络
*/
map.get(nb).add(nc);
map.get(nb).addAll(map.get(nc));
map.get(nc).clear();
map.put(nc,map.get(nb));
Iterator iterator = map.get(nb).iterator();
/*
* *这里将确认一下nb中的网络节点是否全部指向nb的网络
* */
while (iterator.hasNext()) {
Node n1=(Node)iterator.next();
if(!map.get(n1).equals(map.get(nb))) {
map.put(n1,map.get(nb));
}
}
}
//操作2 发消息
} else {
//创建消息,找到node节点对应的网络,进行广播消息
Message message = new Message(i, c);
Node node = list.get(b-1);//取出信息发往的目标节点
//遍历目标节点映射的网络中所有的节点,以此发送消息
Iterator iterator = map.get(node).iterator();
while (iterator.hasNext()) {
Node n1=(Node)iterator.next();
n1.addMessage(message);
}
}
}
//输出消息长度
int a = n - 1;
for (int i = 0; i < a; i++) {
System.out.print(getSum(list.get(i)) + " ");
}
System.out.print(getSum(list.get(a)));
}
//计算节点内信息总长度
public long getSum(Node node) {
long sum = 0;
for (Message m : node.messagelist) {
sum += m.size;
}
return sum;
}
//节点
class Node {
int num;//编号
List<Message> messagelist = new ArrayList<Message>();//消息缓存
HashSet<Node> nodelist = new HashSet<Node>();//节点的网络
public Node(int n) {
this.num = n+1; //+1是方便使用,没用到
}
//判断消息是否存在,不存在则添加
public boolean addMessage(Message m) {
int len = messagelist.size();
//消息列表有消息,需要判重,
if (len > 0) {
//根据题意,这里只需要判断列表中最后一个消息与当前要添加的消息是否一致
if (!messagelist.get(len - 1).equals(m)) {
messagelist.add(m);
return true;
}
//消息列表无消息,直接添加
} else {
messagelist.add(m);
return true;
}
return false;
}
}
//消息
class Message {
int num;// 第几次操作时发出的消息,用于判重
int size;//长度
public Message(int n, int s) {
this.num = n;
this.size = s;
}
}
}