蓝桥杯模拟赛--风险度量--并查集

    xiaoxiao2021-03-25  130

    X星系的的防卫体系包含 n 个空间站。这 n 个空间站间有 m 条通信链路,构成通信网。 两个空间站间可能直接通信,也可能通过其它空间站中转。 对于两个站点x和y (x != y), 如果能找到一个站点z,使得: 当z被破坏后,x和y无法通信,则称z为关于x,y的关键站点。 显然,对于给定的两个站点,关于它们的关键点的个数越多,通信风险越大。 你的任务是:已知网络结构,求两站点之间的通信风险度,即:它们之间的关键点的个数。 输入数据第一行包含2个整数n(2 <= n <= 1000), m(0 <= m <= 2000),分别代表站点数,链路数。 空间站的编号从1到n。通信链路用其两端的站点编号表示。 接下来m行,每行两个整数 u,v (1 <= u, v <= n; u != v)代表一条链路。 最后1行,两个数u,v,代表被询问通信风险度的两个站点。 输出:一个整数,如果询问的两点不连通则输出-1. 例如: 用户输入: 7 6 1 3 2 3 3 4 3 5 4 5 5 6 1 6 则程序应该输出: 2 资源约定: 峰值内存消耗(含虚拟机) < 256M

    CPU消耗 < 2000ms

    用并查集做这道题:这个讲的挺好的:http://www.cnblogs.com/TonyNeal/p/bingchaji.html

    思路:用并查集储存输入数据;看是否连通;否直接输出-1;

    是则遍历删除每一个点,再用并查集储存删除后的数据,看是否连通;

    不能连通,这个点就是关键点;

    画了个很蠢的图:

    表格里是每次输入数据pre[i]的变化;i代表从1-n的节点;pre[i]代表i这个节点的父节点;

    通过join函数连接后,你会发现图右边里的点都被连上了;比如找1和6:操作完后的1的父节点是3,3的父节点是6,6的父节点是6;则1和6是连通的

    并查集算法和路径压缩

    http://www.cnblogs.com/TonyNeal/p/bingchaji.html

    import java.util.Scanner; public class 风险度量2 { static int pre[]; private static int count; public static void main(String[] args) { // TODO Auto-generated method stub Scanner input = new Scanner(System.in); int n = input.nextInt(); int m = input.nextInt(); int init[][] = new int[n][2]; pre = new int[n+1]; for (int i = 1; i < pre.length; i++) { pre[i] = i;//现在从1到n节点的父节点都是自己;设置i为根节点 } //连接两个点 for (int i = 0; i < m; i++) { init[i][0] = input.nextInt(); init[i][1] = input.nextInt(); join(init[i][0],init[i][1]); } //要判断的两个点 int start = input.nextInt(); int end = input.nextInt(); if (find(start)!=find(end)) {//如果不连通直接结束了 System.out.println("-1"); return; } //现在遍历每个点,去掉这个点,剩下的点再重新用并查集找跟节点;若start和end连不上了,说明这个点是关键点 for (int i = 1; i <= n; i++) {//1-n个点 //如何去掉这个点呢?跟程序开头一样,只要init[j]数组里面有i这个点的都不进行join操作; if (i==start||i==end) { continue;//不可能把两个端点去了吧。 } for (int j2 = 1; j2 <= n; j2++) { //既然和程序开头一样,那么pre也要重置才行; pre[j2] = j2;//切记复制的时候变量要改啊。。。 } for (int j = 0; j < m; j++) { if (init[j][0]==i||init[j][1]==i) { continue;//这一步就是去掉i这个点 }else { join(init[j][0], init[j][1]); } } if (find(start)!=find(end)) { count++;//连接不上,这是个关键点 } } System.out.println(count); } /** * @param i i节点 * @param j j节点 */ private static void join(int i, int j) { // TODO Auto-generated method stub i = find(i);//i=i的父节点;取出pre[i]; j = find(j); if (i!=j) {//如果i和j的父节点不一样,让j成为i的父节点; pre[i] = j; } } /** * @param i * @return i的根节点 */ private static int find(int i) { // TODO Auto-generated method stub int x = i; while (x!=pre[x]) {//如果i的父节点不是自己;意思i不是根节点 x = pre[x]; } //路径压缩,让i到根节点上的所有点的父节点都变成根节点; int y = i; int temp = 0; while (y!=x) {//y不等于根节点的时候 temp = pre[y];//临时变量记录y的父节点; pre[y]=x;//y的父节点直接变成根节点; y = temp;//令y等于y的父节点,便于把他父节点的父节点也变成根节点; } return x; } }

    转载请注明原文地址: https://ju.6miu.com/read-11558.html

    最新回复(0)