回溯法解决部落冲突问题

实验内容

原始部落byteland中的居民为了争抢有限的资源,经常发生冲突。几乎每个居民都有它的仇敌。部落酋长为了组织一支保卫部落队友,希望从部落的居民中选出最多的居民入伍,并保证队伍中任何两个人都不是仇敌。

问题描述

算法设计:给定byteland部落中居民间的仇敌关系,计算组成部落卫队的
最佳方案。
输入:首先输入两个正整数n和m,表byteland部落中有n个居民,居民间有m个仇敌关系,居民编号为1,2,。。,n。接下来输入m对正整数,每对正整数包含u和v,表示居民u和居民v是仇敌。
结果:首先输出部落卫队最佳组件方案中包含居民人数,即最优值。之后逐个输出卫队组成,这是一个0-1向量,0表示不在卫队中,1表示在卫中,最优解。

思路分析

此问题于求解最大团的问题类似,是求解最大独立集的问题。我们可以将部落中两两之间的敌对关系抽象为在一个无向图中两个点的连线,没有连线的两个点即是没有敌对关系的两个人。
此题中,我们用树表示解空间。解最大独立集的回溯法与解最大团的问题十分相似。设当前扩展节点Z位于解空间的第i层。在进入左子树前,必须确认从顶点i到已经选入的顶点集中每一个顶点都没有边连接他们任何两个,这是一个约束条件,因为在部落冲突中,没有边相连意味着没有敌对关系,只有没有与其他部落战士有敌对关系的部落战士才可以进入部落护卫队。
在进入右子树之前,必须确认有足够多的而可选择定点使得算法有可能在右子树找到更大的独立集。

方法步骤

具体实现时,我们手下给出部落的人数n和敌对关系的对数m,然后做一个有n个顶点的图,顶点之间的连线关系按照m个敌对关系来确定,有敌对关系的两个部落战士,就把他们连起来,这样问题就转化为了寻找这有n个顶点无向图最大独立集。我们用邻接矩阵表示图G。整型数组v返回所找到的最大的独立集。v[i]=1当且仅当顶点i属于找到的最大独立集。
算法的效率:最大独立集的回溯算法所需的计算时间显然是O(n*2^n)

实验代码

package PAR;

import java.util.Scanner;

public class byteland {
	 
		    static int[] x;//当前子集                                           
		    static int n;//二叉树层数,即部落总人数
		    static int cn;//当前队伍人数
		    static int bestn;//最大队伍人数
		    static int[] bestx;//最优解
		    static int[][] a;//表示队伍人员关系的邻接矩阵
		    /**回溯法解最大团算法(部落冲突问题)
		     * @param i   当前层数
		     */
		    public static void backTrack(int i){
		        if(i>n-1){
		            for(int b=0;b<n;b++){
		                bestx[b]=x[b];
		                
		                
		            }
		            bestn=cn;
		            return;
		        }
		        boolean ok=true;//临界条件:与任一已入选护卫队的队员无仇
		        for(int j=0;j<i;j++){
		            if(x[j]==1&&a[i][j]==1){
		                ok=false;
		                break;
		            }
		        }
		        if(ok){
		            x[i]=1;
		            cn++;
		            backTrack(i+1);
		            cn--;
		        }
		        if((cn+(n-i-1))>bestn){    //这里的n要减一
		            x[i]=0;
		            backTrack(i+1);
		        }
		    }

	       	
		    public static void main(String[] args)
		    {   
		    	System.out.println("输入有多少个战士需要筛选");  
		    	Scanner input =new Scanner(System.in);
	       	    n=input.nextInt();                 //这里的n千万不能加上int 否则就是重新定义,下面就全都用不了了
	       	    cn=0;
		        bestn=0;
		        bestx=new int[n];
		        x=new int[n];
		        a=new int[n][n];
		        System.out.println("输入有缩少对敌对关系");  
	    	    int d=input.nextInt();
	    	    System.out.println("输入敌对关系的二维矩阵");  
		        int [][]m=new int[d][2];       //图的临接矩阵   ,这里应该就是存储两个士兵之间的敌对关系的   ,这里其实还要把敌对关系转化成邻接矩阵的
	    	    for (int i=0;i<d;i++) {
	    		 m[i][0]=input.nextInt();
	    		 m[i][1]=input.nextInt();             
	    	 }

		        //这里构造邻接矩阵时由于书上的算法是从下标一开始的,所以第一行和第一列都不用,拿来当作标签了
		       	 for (int i=0;i<d;i++) {
		       		 a[m[i][0]-1][m[i][1]-1]=1;
		       		 a[m[i][1]-1][m[i][0]-1]=1;
		       	 }

		        backTrack(0);
		        System.out.println("队伍最大人数达: "+bestn);
		        System.out.print("最优解的向量矩阵为:");
		        for(int i=0;i<bestx.length;i++){
		            
		                System.out.print(bestx[i]+" ");
		            
		        }
		    }
		    

		



  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值