最大团问题-分支界限法

  1. 遍历所有点构造二叉树;

  2. 广度遍历树,遍历过程中判断当前结点的点数据时,是否构成完全子图,如果不能则只将右结点加入队列,每次选取队列中完全子图最大的结点作为活结点,无子结点时到达叶子结点,记录为一个完全子图,优先队列法中第一个完全子图即为最优解。

package test;

import java.util.*;

/**
 * Created by saishangmingzhu on 2018/12/10.
 * 最大团问题
 */
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}};

    public static void main(String[] arg){
        new MaximumCliqueProblem().branchAndBoundMethod();
    }

    /**
     * 分支界限法-优先队列式
     * 优先队列式求解时,到达第一个没有子结点的活结点时,即为最优解
     */
    public void branchAndBoundMethod() {
        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】广度遍历
        List<Node> currentLiveNodeList=new ArrayList<>();
        currentLiveNodeList.add(root);
        while (true) {
            //排序
            Node parent = currentLiveNodeList.get(0);
            if (parent.leftNode==null){
                //表示到了叶子结点,进行记录
                //点不算子图,所以要去除点集为1的叶子
                break;
            }
            List<Point> leftPointList = parent.leftNode.hasPointList;
            if (judge(leftPointList) != 0) {
                currentLiveNodeList.add(parent.leftNode);
            }
            //因为右结点是空,所以不需要判断
            //List<Point> rightPointList=parent.rightNode.hasPointList;
            currentLiveNodeList.add(parent.rightNode);
            currentLiveNodeList.remove(parent);
            Collections.sort(currentLiveNodeList, new Comparator<Node>() {
                @Override
                public int compare(Node o1, Node o2) {
                    return o2.hasPointList.size()-o1.hasPointList.size();
                }
            });
        }
        System.out.println("最大团");
        for (Point point:currentLiveNodeList.get(0).hasPointList){
            System.out.print(point.name+",");
        }

    }

    /**
     * 判断现有节点是否是完全子图 -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<>();

    }
}