最大團問題-回溯法

        最大團問題屬於圖論裏的經典問題,典型的案例是找出朋友圈關係圖中最大的圈子,即兩兩相識的最大圈子。

        這裏給出使用回溯法求解的兩個方案:

        方案一: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<>();

    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章