蓝桥杯2020年真题:网络分析

题目

时间限制: 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≤201≤m≤100。 
对于 50% 的评测用例,1≤n≤1001≤m≤1000。 
对于 70% 的评测用例,1≤n≤10001≤m≤10000。 
对于所有评测用例,1≤n≤100001≤m≤1000001≤t≤100

答案

package competition4;

import java.util.Scanner;
/*
5 7
1 1 2
1 1 3
1 4 5
2 1 1
2 4 1
1 3 5
2 1 10
 */
public class NetworkProblem
{
    
    
	/*
	 * 这里我想的是使用类似Kruskal算法里面的找一个节点的顶点的算法(类似并查集)
	 * 这里也是想将它们弄成一棵树,如果某个节点发送了一条数据,
	 * 那么谁会进行接受呢?这里会将所有的节点的顶点和发送数据的这个节点
	 * 的顶点相同的话,就全部保存当前节点发送的数据
	 * 但是后面我就发现它和最小生成树有着本质的不一样的需求,最小生成树只要确保顶点是否是一样就行
	 * 而它在发送数据的时候因为不知道从哪里开始,那么就得需要知道每一个和它相连的节点
	 * 如果是找父节点还行,但是这里还需要寻找所有的子节点,所以这里的方法不可行,
	 * 比如上面的数据就不能通过
	 */
	public static int n,m;
	public static void main(String[] args)
	{
    
    
		 int[][] graph;
		Scanner in = new Scanner(System.in);
		n=in.nextInt();
		m=in.nextInt();
		//这里2+1和n+1都是为了方便我自己操作数据
		//其中一行用来保存当前节点的顶点是谁,另外一行表示当前节点保存的数据的大小
		graph=new int[2+1][n+1];
		
		int temp,start,end;
		
		for(int x=1;x<=m;x++)
		{
    
    
			temp=in.nextInt();
			start=in.nextInt();
			end=in.nextInt();
			if(temp==1)
			{
    
    
				if(graph[1][end]!=0)
				{
    
    
					graph[1][start]=graph[1][end];
				}
				else
				{
    
    
					graph[1][start]=end;					
				}
			}
			else
			{
    
    
				graph[2][start] +=end;
				//如果它不是顶点:那么它就是自己单独的,要么就是肯定有顶点
				if(graph[1][start]!=0)
				{
    
    
					int index=graph[1][start];
					//这里需要注意一下,就因为题目的两台主机,如果网络已经连接好了
					//后面可能还会继续进行连接,那么就会出现当前节点的顶点就是自己
					if(index != start)
						graph[2][index] +=end;
					
					for(int y=1;y<=n;y++)
					{
    
    
						if(graph[1][y]==index && y!=start && y!=index)
						{
    
    
							graph[2][y] +=end;
						}
					}
				}
				//那么现在它自己是顶点,将全部顶点是它的加上它发送的数据大小
				else
				{
    
    
					for(int y=1;y<=n;y++)
					{
    
    
						if(graph[1][y]==start && y!=start)
						{
    
    
							graph[2][y] +=end;
						}
					}
				}
			}
		}
		in.close();
		//最后将每个节点的数据量大小输出
		for(int x=1;x<=n;x++)
		{
    
    
			System.out.print(graph[2][x]+" ");
		}
	}
}

改进

这里采用的是并查集,但是应该只能通过70%的数据,
因为上面的测试用例中1≤n≤100001≤m≤100000,这里算法复杂度是n*m
package competition4;

import java.util.HashSet;
import java.util.Scanner;
/*
5 7
1 1 2
1 1 3
1 4 5
2 1 1
2 4 1
1 3 5
2 1 10
 */
public class NetworkProblem3
{
    
    
	public static int n,m;
	public static void main(String[] args)
	{
    
    
		Scanner in = new Scanner(System.in);
		n=in.nextInt();
		m=in.nextInt();
		//表示每个节点存储的数据大小
		int[] weight=new int[n+1];
		
		int temp,start,end;
		//初始化并查集工具
		UF uf = new UF(n);
		for(int x=1;x<=m;x++)
		{
    
    
			temp=in.nextInt();
			start=in.nextInt();
			end=in.nextInt();
			if(temp==1)
			{
    
    
				if (uf.find(start) != uf.find(end))
				{
    
    
					uf.union(start,end);
				}
			}
			else
			{
    
    
				int i = uf.find(start);
				for(int z=1;z<uf.parent.length;z++)
				{
    
    
					if(uf.parent[z]==i)
					{
    
    
						weight[z] +=end;
					}
				}
			}
		}
		for(int x=1;x<weight.length;x++)
		{
    
    
			System.out.print(weight[x]+" ");
		}
	}
	private static class UF
	{
    
    
		int n;
		int[] parent;

		public UF(int n)
		{
    
    
			this.n = n;
			parent = new int[n + 1];
			for (int i = 1; i <= n; i++)
			{
    
    
				parent[i] = i;
			}
		}
		//查找哪一个节点,就会将和这个节点相连的所有节点的顶点都设置成当前顶点
		int find(int x)
		{
    
    
			return parent[x]==x?x:parent[x];
		}
		//将某个节点加入到某个并集里面,
		//那么也需要将这两个节点本来所在的集合的全部节点的顶点都修改成同一个顶点
		void union(int a, int b)
		{
    
    
			HashSet<Integer> path = new HashSet<>();
			int end1=parent[a]==a?a:parent[a];
			int end2=parent[b]==b?b:parent[b];
			for(int x=1;x<parent.length;x++)
			{
    
    
				if(parent[x]==end1 || parent[x]==end2)
				{
    
    
					path.add(x);
				}
			}
			for (Integer xx : path)
			{
    
    
				parent[xx] = end1;
			}
			parent[end2] = end1;
		}
	}
}

网上大佬的思路

我觉得这个写得还是挺好的,里面虽然进行深度的dfs
但是有bool数组进行截枝,所以应该不会栈溢出的,应该也能通过所有测试样例
package competition4;

import java.util.LinkedList;
import java.util.Scanner;

public class NetworkProblemOfOther2
{
    
    
	static int[] data;
	static boolean[] bool;
	static LinkedList<LinkedList<Integer>> list = new LinkedList<LinkedList<Integer>>();

	public static void main(String[] args)
	{
    
    
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		data = new int[n + 1];
		bool = new boolean[n + 1];
		int a = 0, b = 0, c = 0;
		for (int i = 0; i <= n; i++)
		{
    
    
			list.add(new LinkedList<>());
		}
		for (int i = 0; i < m; i++)
		{
    
    
			a = sc.nextInt();
			b = sc.nextInt();
			c = sc.nextInt();
			if (a == 1)
			{
    
    
				list.get(b).add(c);
				list.get(c).add(b);
			} else
			{
    
    

				bool = new boolean[n + 1];
				dfs(b, c);
			}
		}
		for (int i = 1; i <= n; i++)
		{
    
    
			System.out.print(data[i]+" ");
		}
	}
	public static void dfs(int node, int num)
	{
    
    
		bool[node] = true;
		data[node] += num;
		LinkedList<Integer> templist = list.get(node);
		for (int i : templist)
		{
    
    
			if (!bool[i])
			{
    
    
				dfs(i, num);
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_43416157/article/details/109006265