日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法:程序设计之并查集

發布時間:2025/3/20 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法:程序设计之并查集 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

? 之前一直都是聽說并查集,感覺是一個神乎其技,狂拽酷炫。卻沒有想過在自己學習并查集之前,自已在解決問題的時候也能夠想到一個和并查集異曲同工的方法。這個還是很愉快的。


版權說明

著作權歸作者所有。
商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
作者:Coding-Naga
發表日期: 2015年9月27日
鏈接:http://blog.csdn.net/lemon_tree12138/article/details/48690181
來源:CSDN
更多內容:分類 >> 算法與數學


北大OJ實例

原題描述

?

思路分析

? 按照上面的題目意思,我們先來看一些示例:D 1 2, D 2 3, D 4 5, D 5 6

? 上面的例子里我們可以作這樣的一個劃分( (1,2,3) (4,5,6) )

? 劃分的依據是能不能夠確定兩個案件是否相關。比如我可以確定1和2不是同一個團伙犯案,2和3不是同一個團伙犯案,1和3是同一個團伙犯案。在經過這樣的劃分之后,在時間的推移下,每個劃分的集合是越來越大,集合的個數也是越來越多。

1.構造動態集合

? 題目中說,我們需要按照時間的順序來做邏輯輸出。在這種有諸多不能確定事物的情況下,我們很容易就可以想到使用鏈表的結構來保存。Java中,我們有List類就可以。

2.標記數組

? 上面使用了鏈表的結構來解題。不過,不幸的是在OJ的編譯器里不支持List這個結構。在我們提交代碼之后,會報出一個編譯錯誤。不過在整個思路中我們有一點是一致的,那就是我們需要把這些案件劃分成幾個不同的集合。每個集合里面的元素是相關的,是同一個團伙犯的案,不是同一個團伙犯的案。

? 那么我們的做法是這樣的,首先定義一個大小為案件總數的數組,這個數組是用來標記每個案件是屬于哪個集合。在集合內部,有兩個互為相反數的標記,是用來標記是不是屬于同一個犯罪團伙犯的案。隨著時間的推移,我們需要不斷修正這些集合。下面會有代碼的實現部分。

3.并查集

? 基于上面的標記數組。我們可以擴展到并查集的使用。并查集的做法是在每個集合中標記元素的上一級,以后需要比較任意兩個案件的關系時,只要比較他們最上面的那個祖先是否是同一個就可以判斷他們是否是屬于同一個集合。當然,Java中沒有C中的指針一說,所以,這里我們還是使用數組來保存標記信息。

? 些過并查集的讀者應該都知道,在并查集不斷擴大的過程中,可能會有并查集的樹結構在不斷長高。而我們查詢的時間復雜度就是和我們的樹的高度有關。所以,我們要想一個辦法讓我們的樹結構的高度小下來。這里,我們有兩種方法來解決問題。第一種:在每次查找祖先節點時,我們把某些節點先前移動;第二種:我們每次合并樹時都必須遵從把小樹加到大樹中,而不是把大樹加到小樹上。在下面的代碼里,我們使用的是第二種方法來解決樹的路徑壓縮。


代碼實現

1.鏈表實現

public class Main_0 {private final static String NOT_SURE_LABEL = "Not sure yet.";private final static String DIFFERENT_GANGS_LABEL = "In different gangs.";private final static String SAME_GANG_LABEL = "In the same gang.";private final static int NOT_INTERSECTION = 0; // 000private final static int ONE_INTERSECTION_ONE = 2; // 010private final static int ONE_INTERSECTION_TWO = 1; // 001private final static int TWO_INTERSECTION_ONE = 6; // 110private final static int TWO_INTERSECTION_TWO = 5; // 101private static String[][] getData(Scanner inputScanner, int m) {String[][] data = new String[m][3];String message = "";inputScanner.nextLine();for (int i = 0; i < data.length; i++) {message = inputScanner.nextLine();data[i] = message.split(" ");}return data;}private static int intersection(Determined x, Determined y) {for (int i = 0; i < y.oneList.size(); i++) {if (x.oneList.contains(y.oneList.get(i))) {return ONE_INTERSECTION_ONE;}}for (int i = 0; i < y.oneList.size(); i++) {if (x.twoList.contains(y.oneList.get(i))) {return TWO_INTERSECTION_ONE;}}for (int i = 0; i < y.twoList.size(); i++) {if (x.oneList.contains(y.twoList.get(i))) {return ONE_INTERSECTION_TWO;}}for (int i = 0; i < y.twoList.size(); i++) {if (x.twoList.contains(y.twoList.get(i))) {return TWO_INTERSECTION_TWO;}}return NOT_INTERSECTION;}private static void merge(Determined x, Determined y, int type) {switch (type) {case ONE_INTERSECTION_ONE:case TWO_INTERSECTION_TWO:for (int i = 0; i < y.getOneList().size(); i++) {if (!x.getOneList().contains(y.getOneList().get(i))) {x.addNewOne(y.getOneList().get(i));}}for (int i = 0; i < y.getTwoList().size(); i++) {if (!x.getTwoList().contains(y.getTwoList().get(i))) {x.addNewTwo(y.getTwoList().get(i));}}break;case ONE_INTERSECTION_TWO:case TWO_INTERSECTION_ONE:for (int i = 0; i < y.getOneList().size(); i++) {if (!x.getTwoList().contains(y.getOneList().get(i))) {x.addNewTwo(y.getOneList().get(i));}}for (int i = 0; i < y.getTwoList().size(); i++) {if (!x.getOneList().contains(y.getTwoList().get(i))) {x.addNewOne(y.getTwoList().get(i));}}break;default:break;}}private static void arrange(List<Determined> sureList) {for (int i = sureList.size() - 1; i >= 0; i--) {for (int j = i - 1; j >= 0; j--) {int interResult = intersection(sureList.get(j), sureList.get(i));if (interResult != NOT_INTERSECTION) {merge(sureList.get(j), sureList.get(i), interResult);sureList.remove(i);}}}}private static void answer(List<Determined> sureList, String one, String two) {for (int i = 0; i < sureList.size(); i++) {if (sureList.get(i).getOneList().contains(one) && sureList.get(i).getOneList().contains(two)) {System.out.println(SAME_GANG_LABEL);return;} else if (sureList.get(i).getOneList().contains(one) && sureList.get(i).getTwoList().contains(two)) {System.out.println(DIFFERENT_GANGS_LABEL);return;} else if (sureList.get(i).getOneList().contains(two) && sureList.get(i).getTwoList().contains(one)) {System.out.println(DIFFERENT_GANGS_LABEL);return;}}System.out.println(NOT_SURE_LABEL);}private static void printAnswers(String[][] data, int n) {List<Determined> sureList = new ArrayList<Main_0.Determined>();Determined newDetermined = null;for (int i = 0; i < data.length; i++) {if (data[i][0].equals("D")) {// 先添加到sureList中newDetermined = new Main_0.Determined();newDetermined.addNewOne(data[i][1]);newDetermined.addNewTwo(data[i][2]);sureList.add(newDetermined);// 再整理sureListarrange(sureList);} else {answer(sureList, data[i][1], data[i][2]);}}}public static void main(String[] args) {Scanner inputScanner = new Scanner(System.in);int t = inputScanner.nextInt();while (t-- > 0) {int n = inputScanner.nextInt();int m = inputScanner.nextInt();String[][] data = getData(inputScanner, m);printAnswers(data, n);}}static class Determined {private List<String> oneList = new ArrayList<>();private List<String> twoList = new ArrayList<>();public List<String> getOneList() {return oneList;}public void setOneList(List<String> oneList) {this.oneList = oneList;}public void addNewOne(String newOne) {oneList.add(newOne);}public List<String> getTwoList() {return twoList;}public void setTwoList(List<String> twoList) {this.twoList = twoList;}public void addNewTwo(String newTwo) {twoList.add(newTwo);}} }


2.標記數組(并查集前導)

import java.util.Scanner;public class Main {private final static String NOT_SURE_LABEL = "Not sure yet.";private final static String DIFFERENT_GANGS_LABEL = "In different gangs.";private final static String SAME_GANG_LABEL = "In the same gang.";private static String[][] getData(Scanner inputScanner, int m) {String[][] data = new String[m][3];String message = "";inputScanner.nextLine();for (int i = 0; i < data.length; i++) {message = inputScanner.nextLine();data[i] = message.split(" ");}return data;}private static void answer(int[] cases, int one, int two) {if (cases[one] == 0 || cases[two] == 0) {System.out.println(NOT_SURE_LABEL);return;}if (cases[one] == cases[two]) {System.out.println(SAME_GANG_LABEL);} else if (cases[one] == -cases[two]) {System.out.println(DIFFERENT_GANGS_LABEL);} else {System.out.println(NOT_SURE_LABEL);}}private static void printAnswers(String[][] data, int n) {int[] cases = new int[n]; // 記錄案件信息(標記犯罪團伙)for (int i = 0; i < data.length; i++) {if (data[i][0].equals("D")) {// 先添加到sureList中int one = Integer.valueOf(data[i][1]);int two = Integer.valueOf(data[i][2]);if (cases[one] == 0 && cases[two] == 0) {cases[one] = i + 1;cases[two] = -(i + 1);} else if (cases[one] != 0 && cases[two] == 0) {cases[two] = -cases[one];} else if (cases[one] == 0 && cases[two] != 0) {cases[one] = -cases[two];} else if (Math.abs(cases[one]) != Math.abs(cases[two])) {int flagCase = cases[two];for (int j = 0; j < cases.length; j++) {if (cases[j] == flagCase) {cases[j] = -cases[one];} else if (cases[j] == -flagCase) {cases[j] = cases[one];}}}} else {answer(cases, Integer.valueOf(data[i][1]),Integer.valueOf(data[i][2]));}}}public static void main(String[] args) {Scanner inputScanner = new Scanner(System.in);int t = inputScanner.nextInt();while (t-- > 0) {int n = inputScanner.nextInt();int m = inputScanner.nextInt();String[][] data = getData(inputScanner, m);printAnswers(data, n);}} }

3.并查集實現

import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;/*** 并查集*/ public class Main {private final static String NOT_SURE_LABEL = "Not sure yet.";private final static String DIFFERENT_GANGS_LABEL = "In different gangs.";private final static String SAME_GANG_LABEL = "In the same gang.";private static int[] parents = null;private static int[] classifys = null;private static int[] size = null;static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));private static void answer(int x, int y) {int px = find(x);int py = find(y);if (px != py) {System.out.println(NOT_SURE_LABEL);} else {if (classifys[x] == classifys[y]) {System.out.println(SAME_GANG_LABEL);} else {System.out.println(DIFFERENT_GANGS_LABEL);}}}private static void printAnswers(int m, int n) throws IOException {for (int i = 0; i < m; i++) {String[] data = reader.readLine().split(" ");if (data[0].equals("D")) {int x = Integer.valueOf(data[1]);int y = Integer.valueOf(data[2]);union(x, y);} else {answer(Integer.valueOf(data[1]), Integer.valueOf(data[2]));}}}private static int find(int x) {if (parents[x] == x) {return x;}int p = find(parents[x]);classifys[x] = (classifys[x] + classifys[parents[x]]) % 2;parents[x] = p;return p;}private static void union(int x, int y) {int px = find(x);int py = find(y);if (px != py) {if (size[px] <= size[py]) {parents[px] = py;classifys[px] = (classifys[x] + classifys[y] + 1) % 2;size[py] += size[px];} else {parents[py] = px;classifys[py] = (classifys[x] + classifys[y] + 1) % 2;size[px] += size[py];}}}private static void initFlagArray(int n) {parents = new int[n + 1];for (int i = 0; i < parents.length; i++) {parents[i] = i;}classifys = new int[n + 1];size = new int[n + 1];for (int i = 0; i < size.length; i++) {size[i] = 1;}}public static void main(String[] args) {int t = 0;try {t = Integer.parseInt(reader.readLine());while (t-- > 0) {String[] mn = reader.readLine().split(" ");int n = Integer.parseInt(mn[0]);int m = Integer.parseInt(mn[1]);initFlagArray(n);printAnswers(m, n);}} catch (NumberFormatException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}} }

總結

以上是生活随笔為你收集整理的算法:程序设计之并查集的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。