分支限界法

 什么是分支限界法?

        广度优先搜索是—种依照“由近及远,按层展开”的策略进行的枚举算法,也意味着它需要遍历整个状态空间图,导致算法效率不高。给定一个问题的状态间表示,设计搜索算法时需要考虑以下两个事实
       ◆并不是所有的分支都包含可行解
       ◆并不是所有的分支都包含最优解
      分支限界算法=广度优先搜索+剪枝策略

      分支限界算法需要设计合适的剪枝策略,限制某些分支的扩展,尽量避免不必要的搜索。常用的剪枝策略包括两大类
     1.约束函数剪枝:根据约束条件,状态空间图中的部分状态可能是不合法的。因此,在状态空间图中以不合法状态为根的分支不包含可行解,故其分支可以剪枝。
     2.限界函数剪枝:这种策略一般应用于最优化问题。假设搜索算法当前访问的状态为S,且存在一个判定函数:它能判定以S为根的分支不包含最优解,因此该分支可以剪除而无需搜索


    约束函数剪枝可以剪除状态空间图中的不可行解
    限界函数剪枝用于剪除状态空间图中的可行但是非最优的解

             

经典应用

       装载问题
       0-1背包问题
       旅行商问题
       最短路径问题

 

装载问题:

 

TSP问题:

借鉴:https://blog.csdn.net/qq_35649945/article/details/93056866

问题描述:

       旅行家要旅行n个城市,已知各城市之间的路程。要求选定一条从驻地出发经过每个城市一次,最后回到驻地的路线,使总的路程最小。例如:从如图中的无向带权图G=(V,E)中的1号点出发,经过图中的每个点,并且不能重复,然后回到1号点,要求经过的路径长度是最短的(即求图中 路径 )。

                                          å¨è¿éæå¥å¾çæè¿°

算法思想:

定义解空间树后,对解空间进行搜索,需要先找到限界条件和约束条件
(1)约束条件:如果带权邻接矩阵maps[i][j]不为无穷,即<i,j>能走通,否则继续寻找能走通的路。队列不为空。
(2)限界条件:cl<bestw,cl初始值为0,bestw初始值为无穷。
   cl表示当前已走过的路径长度。
搜索过程:
       将满足条件(即上一层节点的路径长度+上层节点到扩展节点的长度<bestw)的节点加入队列,为了加快搜索速度,使用优先队列,优先队列中的优先级为已走过的路径长度cl,cl值越小,越优先。

                                   

import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Scanner;
class Node1{
	int  cl; //已经走过的路径长度
	int id;//表示所在解空间树的第几层
	int x[]=new int[105];//存储路径
	public Node1(int cl,int id){
		this.cl=cl;
		this.id=id;
	}
}
public class Main {
	   static final int MAX=105;
	   static final int INF=(int)1e9;
	   //优先队列存储,每次自动排序,cl小的优先处理
	   static PriorityQueue<Node1> q=new PriorityQueue<Node1>(new Comparator<Node1>() {
			    	      public int compare(Node1 o1, Node1 o2) {
			    	    	       if(o1.cl>o2.cl) return 1;
			    	    	       else return -1;
			    	      }
				});
	   static int g[][]=new int[MAX][MAX];
	   static int bestw;//最短路径长度
	   static int best[]=new int[MAX];//最短路径
	   static int n,m;//n个点,m条边
	   static void bfs(){
		         Node1 node=new Node1(0,2);//初始经过的路径为0,起点1位于第树的第二层
		         for(int i=1;i<=n;i++)
		        	    node.x[i]=i;
		         q.add(node);
		         while(!q.isEmpty()){
		        	      Node1 newnode=q.poll();
		        	      int t=newnode.id;
		        	      if(t==n){
		        	    	     if(g[newnode.x[t-1]][newnode.x[n]]!=INF && g[newnode.x[n]][newnode.x[1]]!=INF){
		        	    	    	     if(newnode.cl+g[newnode.x[t-1]][newnode.x[n]]+g[newnode.x[n]][newnode.x[1]]<bestw){
		        	    	    	    	      bestw=newnode.cl+g[newnode.x[t-1]][newnode.x[n]]+g[newnode.x[n]][newnode.x[1]];
		        	    	    	    	      for(int i=1;i<=n;i++){
		        	    	    	    	    	     best[i]=newnode.x[i];
		        	    	    	    	      }
		        	    	    	     }
		        	    	     }
		        	      }
		        	      if(newnode.cl>=bestw) continue;//约束条件 两点不可达
		        	      //对当前节点进行扩展子节点
		        	      for(int j=t;j<=n;j++){
		        	    	     if(newnode.cl+g[newnode.x[t-1]][newnode.x[j]]<bestw){ //限界条件
		        	    	    	     int c=newnode.cl+g[newnode.x[t-1]][newnode.x[j]];
		        	    	    	     node=new Node1(c,t+1);
		        	    	    	     for(int i=1;i<=n;i++){
		        	    	    	    	    node.x[i]=newnode.x[i];
		        	    	    	     }
		        	    	    	     //通过交换实现路径节点更新
		        	    	    	     int tmp=node.x[t];
		        	    	    	     node.x[t]=node.x[j];
		        	    	    	     node.x[j]=tmp;
		        	    	    	     q.add(node);
		        	    	     }
		        	      }
		         }
	   }
       public static void main(String[] args) {
    	       Scanner scan=new Scanner(System.in);
		       n=scan.nextInt();
		       m=scan.nextInt();
		       for(int i=0;i<n;i++){
		    	   Arrays.fill(g[i], INF);
		       }
		       for(int i=0;i<m;i++){
		    	   int a=scan.nextInt();
		    	   int b=scan.nextInt();
		    	   int c=scan.nextInt();
		    	   g[a][b]=g[b][a]=c;
		       }
		       bestw=INF;//最短路径初始为0
		       bfs();
		       System.out.println("最短路径长度:"+bestw);
		       for(int i=1;i<=n;i++){
		    	    System.out.println(best[i]);
		       }
		       System.out.println(best[1]);
	  }
}
//4 6
//1 2 15
//1 3 30
//1 4 5
//2 3 6
//2 4 12
//3 4 3


 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OUC_lkc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值