当前位置: 首页 > news >正文

微信小程序跳转到网站百度应用市场下载安装

微信小程序跳转到网站,百度应用市场下载安装,网站建设需要的技术,专业网站搭建运营Day56–图论–108. 冗余的边(卡码网),109. 冗余的边II(卡码网) 今天又是练习并查集的一天。第一题很简单,第二题有多种情况,如果不熟悉图的话,基本上是想不出来的。建议思考超过10分…

Day56–图论–108. 冗余的边(卡码网),109. 冗余的边II(卡码网)

今天又是练习并查集的一天。第一题很简单,第二题有多种情况,如果不熟悉图的话,基本上是想不出来的。建议思考超过10分钟,直接看题解。跟着题解抄一遍,然后再自己写一遍思路,比愣头青去想好,效率更高。

108. 冗余的边(卡码网)

方法:并查集

思路:

使用并查集,将每个边的from to都加到集合里面。

如果发现from to已经在集合里了,就说明他们在同一颗树上。

如果再把他们连起来,就会成环。所以这是要删除的边

import java.util.*;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();Disjoint dj = new Disjoint(n);while (n-- > 0) {int from = in.nextInt();int to = in.nextInt();// 如果发现from to已经在集合里了,就说明他们在同一颗树上// 如果再把他们连起来,就会变成图。所以这是要删除的边if (dj.isSame(from, to)) {System.out.println(from + " " + to);return;} else {// 每个from to都加到集合里面dj.join(from, to);}}}
}class Disjoint {private int[] father;public Disjoint(int n) {father = new int[n + 1];for (int i = 0; i <= n; i++) {father[i] = i;}}public int find(int a) {if (a == father[a]) {return a;} else {return father[a] = find(father[a]);}}public boolean isSame(int o1, int o2) {return find(o1) == find(o2);}public void join(int o1, int o2) {int root1 = find(o1);int root2 = find(o2);if (root1 == root2) {return;}father[o2] = o1;}
}

109. 冗余的边II(卡码网)

方法:并查集

思路:

两个方向

  1. 图中有一个入度为2的点
    • 情况一:如果我们找到入度为2的点,那么删一条指向该节点的边就行了。
    • 情况二,入度为2的点,只能删特定的一条边,因为有可能一删就不成树了,有孤点。
    • 综上,鉴于情况二,我们要模拟删除,看看它删后是否还构成树;鉴于情况一,如果都能删,题目要求要优先删除后面的。
    • 实际代码怎么做?
      • 倒序遍历入度为2的边,模拟删除后,是否还能构成树,能的话删。不能的话,删第二条边。
  2. 图中有一个有向环
    • 删掉构成环的边就行了(和上题差不多)
import java.util.*;public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int[][] edges = new int[n][2];int[] inDegree = new int[n + 1];for (int i = 0; i < n; i++) {int from = in.nextInt();int to = in.nextInt();// 节点to的入度加一inDegree[to]++;edges[i][0] = from;edges[i][1] = to;}// 检查edges中是否有入度为2的节点List<Integer> twoInDegree = new ArrayList<>();// 因为要满足情况一,优先输出后加入的边,需要倒序遍历for (int i = n - 1; i >= 0; i--) {if (inDegree[edges[i][1]] == 2) {// 这里加的这个i是edges中的索引twoInDegree.add(i);}}// 索引值int i;if (twoInDegree.size() > 0) {// 这条是最后加入的边i = twoInDegree.get(0);// 如果删除后仍能构成树,证明是情况一,直接删这条if (isTreeAfterRemove(edges, i, new Disjoint(n))) {} else {// 如果不能构成树,证明是情况二,删另一条i = twoInDegree.get(1);}} else {// 如果没有入度为2的边,走到这里,就是情况三:删除构成有向环的边// 注意,不要传用过的并查集。这里要传一个新的。i = getRemoveEdge(edges, new Disjoint(n));}// 打印输出System.out.println(edges[i][0] + " " + edges[i][1]);}// 模拟删除索引为Index这条边,看看剩下的边是否能构成树private static boolean isTreeAfterRemove(int[][] edges, int index, Disjoint dj) {for (int i = 0; i < edges.length; i++) {// 模拟删除索引为Index这条边,看看剩下的边是否能构成树if (i == index) {continue;}int from = edges[i][0];int to = edges[i][1];// 剩下的from to,还有不在一个图中的,证明存在孤点if (dj.isSame(from, to)) {return false;}dj.join(from, to);}// 模拟删除后,仍然能构成树return true;}// 情况三:删除构成有向环的边。和108冗余的边是一样的操作。private static int getRemoveEdge(int[][] edges, Disjoint dj) {int i=0;for (i = 0; i < edges.length; i++) {int from = edges[i][0];int to = edges[i][1];if (dj.isSame(from, to)) {break;} else {dj.join(from, to);}}return i;}
}// 并查集
class Disjoint {private int[] father;public Disjoint(int n) {father = new int[n + 1];for (int i = 0; i <= n; i++) {father[i] = i;}}public int find(int a) {if (a == father[a]) {return a;} else {return father[a] = find(father[a]);}}public boolean isSame(int o1, int o2) {return find(o1) == find(o2);}public void join(int o1, int o2) {int root1 = find(o1);int root2 = find(o2);if (root1 == root2) {return;}father[o2] = o1;}
}

代码随想录中,给出的Java的版本,写得有点累赘。本篇代码改自卡尔的C++版本题解,自认为写得更加清晰一点。符合卡尔解题的时候用的思路。

勘误:

之前并查集理解得不够透彻,join方法写错了。

原来是:

    public void join(int o1, int o2) {int root1 = find(o1);int root2 = find(o2);if (root1 == root2) {return;}father[o2] = o1;}

现在是:

    public void join(int o1, int o2) {int root1 = find(o1);int root2 = find(o2);if (root1 == root2) {return;}father[root2] = root1;}

为什么必须连接根节点?

假设我们要合并两个节点o1o2,步骤应该是:

  1. 先通过find找到o1的根节点root1o2的根节点root2
  2. 如果root1 != root2,说明两个节点属于不同集合,需要合并。
  3. 合并的是两个集合的根节点(即root2的父节点指向root1),而不是直接让o2的父节点指向o1

举例:

假设现在有两个独立的集合:

  • 集合 1:1是根节点(father[1] = 1),2的父节点是1father[2] = 1)。
  • 集合 2:3是根节点(father[3] = 3),4的父节点是3father[4] = 3)。

现在要合并24(即o1=2o2=4):

  1. 先找根节点:root1 = find(2) = 1root2 = find(4) = 3
  2. 正确的合并:father[root2] = root1(即father[3] = 1)。
    合并后,两个集合的根节点都是1,整个集合结构为:1是根,23的父节点是14的父节点是3

如果错误地写成father[o2] = o1(即father[4] = 2):

  • 此时4的父节点是2,但2的父节点是13的父节点还是3(仍然是独立根节点)。
  • 这会导致34被错误地分割在不同集合中(find(3) = 3find(4) = 1),但实际上4原本属于3的集合,合并后应该同属一个集合。
http://www.dtcms.com/a/531228.html

相关文章:

  • 长春世邦做网站深圳网站公司建设
  • 建设网站需要了解些什么东西建设黑彩网站需要什么
  • 农安县住房城乡建设局网站问题反馈的网站怎么做
  • 怎样建一个自己的网站做网站市场
  • lol网站怎么做百度推广关键词和创意
  • 美词原创网站建设软件开发网络技术开发公司
  • 怎么快速做网站排名建设网站几钱
  • 网站开发项目经验描述商标查询天眼查
  • 宠物网站的设计与实现掏宝网网站建设评价表
  • 做游戏网站要通过什么审核陕西省诚信建设示范网这个网站
  • 丽水专业做网站自己做培训网站
  • 网站搭建合同html网页制作期末作业
  • 免费网站设计软件清远建设局网站
  • 宁波网站建设优化企业简历模板制作
  • 网站建站主题动漫网站设计
  • 网站底部模板源码金蝶网站建设公司案例
  • 网站dns解析设置做外贸网站那个好
  • 网站建设3000字盐城集团网站建设
  • 门户网站改造方案怎么简单页网站
  • 北京城市雕塑建设管理办公室网站wordpress架设主机
  • 超值的网站建设哪里有html5网站建设
  • 在线包车网站建设长沙微网站电话号码
  • 广州手机网站建设公司哪家好开发什么软件有市场
  • 如何用h5做网站芜湖做公司网站
  • 指定网站怎么设置路由器只访问合肥建设工程交易网站
  • 国内网站设计制作长安镇做网站
  • 网站定制电话贴吧网站建设
  • 国防教育网站建设方案文昌市建设局网站
  • 南京网站制作报价微信小程序注册要钱吗
  • 免费建站工具wordpress安装linux