最大團問題屬於圖論裏的經典問題,典型的案例是找出朋友圈關係圖中最大的圈子,即兩兩相識的最大圈子。
這裏給出使用回溯法求解的兩個方案:
方案一:1.遍歷所有點構造二叉樹;
2.深度遍歷樹,遍歷過程中判斷加入當前結點的點數據時,是否構成完全子圖,如果不能則走右結點,即剪枝左結點。達到葉子結點時即爲一個完全子圖的解,進行記錄;
3.選擇最大的記錄作爲最大團。(實現爲如下代碼)
方案二:1.開始遍歷點構造二叉樹時就進行記錄當前達到葉子的最大完全子圖,記錄最大值爲tmpMax,此值會在後續構造二叉樹時更新;
2.繼續遍歷點構造樹的時候,計算當前結點所包含的完全子圖加剩餘結點數是否大於之前記錄的tmpMax,如果不大於,則直接剪枝,因爲哪怕剩下所有結點都包含在完全子圖,也不會大於tmpMax。
package test; import java.util.ArrayList; import java.util.List; /** * Created by saishangmingzhu on 2018/12/9. * 最大團問題 */ public class MaximumCliqueProblem { //圖 private int[][] pointIndex=new int[][]{ {1,1,0,1,1}, {1,1,1,0,1}, {0,1,1,0,1}, {1,0,0,1,1}, {1,1,1,1,1}}; private List<Node> leafNodeList=new ArrayList<>(); public static void main(String[] arg){ new MaximumCliqueProblem().backtracking(); } /** * 回溯法 */ public void backtracking(){ List<Point> pointList=new ArrayList<>(); pointList.add(new Point("1",0)); pointList.add(new Point("2",1)); pointList.add(new Point("3",2)); pointList.add(new Point("4",3)); pointList.add(new Point("5",4)); //【1】構建樹 Node root=new Node(); createTree(pointList, root,0); //【2】深度遍歷+判斷記錄 traversal(root); //【3】選最大 System.out.println("所有子圖"); int size=0; Node maxNode=null; for (Node node:leafNodeList){ if (size<node.hasPointList.size()){ size=node.hasPointList.size(); maxNode=node; } for (Point point:node.hasPointList){ System.out.print(point.name+","); } System.out.println(); } System.out.println("最大團"); for (Point point:maxNode.hasPointList){ System.out.print(point.name+","); } } private void traversal(Node parent){ if (parent.leftNode==null){ //表示到了葉子結點,進行記錄 //點不算子圖,所以要去除點集爲1的葉子 if (parent.hasPointList.size()>1) leafNodeList.add(parent); return; } List<Point> leftPointList=parent.leftNode.hasPointList; if (judge(leftPointList)!=0){ traversal(parent.leftNode); } //因爲右結點是空,所以不需要判斷 //List<Point> rightPointList=parent.rightNode.hasPointList; traversal(parent.rightNode); } /** * 判斷現有節點是否是完全子圖 -1 表示不是 * @param pointList * @return */ private int judge(List<Point> pointList){ for (int i=0;i<pointList.size();i++){ Point pointi=pointList.get(i); int indexi=pointi.index; for (int j=i+1;j<pointList.size();j++){ Point pointj=pointList.get(j); int indexj=pointj.index; //使用[indexi][indexj]是爲了說明問題,可以直接使用[i][j] if (pointIndex[indexi][indexj]!=1){ return 0; } } } return 1; } private void createTree(List<Point> pointList, Node parent,int i) { if (i>=pointList.size()){ return; } Node leftNode=new Node(); leftNode.hasPointList.addAll(parent.hasPointList); leftNode.hasPointList.add(pointList.get(i)); i++; createTree(pointList,leftNode,i); parent.leftNode=leftNode; Node rightNode=new Node(); rightNode.hasPointList.addAll(parent.hasPointList); createTree(pointList,rightNode,i); parent.rightNode=rightNode; } class Point{ private String name; private int index; public Point(String name,int index) { this.name = name; this.index = index; } } class Node{ private Node leftNode; private Node rightNode; private List<Point> hasPointList=new ArrayList<>(); } }