16.Hamilton(哈密顿)回路问题

这个回路问题还好不是很难,就是代码有点多,有很多看不懂

其实哈密顿回路就是说,如上图a中所示,有5个位置点,其中的连线表示两位置点之间可以往来,现在要求从其中某一个点出发,然后遍历所有点后(每个位置点只能走一次)回到起始位置点。它的行进方式还是有很多种的,也没有什么具体条件的要求。

然后b图就是利用回溯算法(其实就是穷尽所有的计算,只不过它的步骤比较系统)来计算可行的行进方式:

假设一开始从位置1出发,然后走向第二个点可选位置有三个,分别是2、3、4,然后在基于第二个位置点的基础上根据连线又可以确定第三个位置点的选择,直到所有的可能性都被穷尽。(其中有一个约束,在行进过程中同一个位置点不能出现2次,一旦出现该行进路线就无效,同时要求遍历完所有的点)

算法伪代码:

(有一部分为回溯的固定模板,后面代码会备注不用改变)

IS-COMPLETE(x)

1.    if A[x[n],x[1]]!=0

2.      then return true

3.    return false

PRINT-SOLUTION(x)

1.    for i<-1 to n

2.      do print x[i],"->"

3.    print x[1]

MAKE-ITERMS

1,    j<-1

2.    for i<-1 to n

3.      do if A[x[k-1],i]!=0

4.           then iterms[j]<-i

5.                  j<-j+1

6.    return iterms

IS-PARTIAL(x,k)

1.    for i<-1 to k-1

2.      do if x[i]=x[k]

3.          then return false

4.    return true

JAVA:

Combineproblem.java

package jamin;
import java.util.Vector;
public abstract class Combineproblem {
public Object a;
public int n;
public Comparable[] x;
public boolean flag;
public abstract boolean iscomplete(int k);
public abstract void printsolution(int k);
public abstract Vector<Comparable> makeiterms(int k);
public abstract boolean ispartial(int k);
}
//固定不变

General.java

package jamin;
import java.util.Vector;
public class General {
public static void backtrack(Combineproblem p) {
    explore(p,0);
    if(!p.flag)
        System.out.println("no sulution!");
}
private static void explore(Combineproblem p,int k) {
    if(k>=p.n) {
        if(p.iscomplete(k)) {
            p.flag=true;
            p.printsolution(k);
        }
        return;
    }
    Vector<Comparable> iterms=p.makeiterms(k);
    for(int i=0;i<iterms.size();i++) {
        p.x[k]=iterms.get(i);
        if(p.ispartial(k))
            explore(p,k+1);
    }
}
}
//固定不变

Hailton.java  //这里是根据上面的伪代码来进行设计的

package jamin;
import java.util.Vector;
public class Hamilton extends Combineproblem{
int start;
public Hamilton(int[][] a,int n,int start) {
    this.a=a;
    this.n=n;
    this.flag=false;
    this.x=new Integer[n];
    this.start=start-1;
}
@Override
public boolean iscomplete(int k) {
    // TODO Auto-generated method stub
    if(k>=n)
        return ((int[][]) a)[(Integer)(x[k-1])][(Integer)(x[0])]==1;
    return false;
}

@Override
public void printsolution(int k) {
    // TODO Auto-generated method stub
    System.out.print(((Integer)(x[0])+1));
    for(int i=1;i<n;i++)
        System.out.print("->"+((Integer)(x[i])+1));
    System.out.println("->"+((Integer)(x[0])+1));
}

@Override
public Vector<Comparable> makeiterms(int k) {
    // TODO Auto-generated method stub
Vector<Comparable> iterms=new Vector<Comparable>();
if(k==0) {
    iterms.add(new Integer(start));
}else {
    for(int i=0;i<n;i++)
        if(((int[][])a)[(Integer)(x[k-1])][i]==1)
            iterms.add(new Integer(i));
}
return iterms;
}

@Override
public boolean ispartial(int k) {
    // TODO Auto-generated method stub
    for(int i=0;i<k;i++)
        if(x[i].compareTo(x[k])==0)
            return false;
    return true;
}
}
 

Test.java

package jamin;

public class Test {
public static void main(String args[]) {
    int a[][]= {{0,1,1,1,0},
            {1,0,1,0,1},
            {1,1,0,1,0},
            {1,0,1,0,1},
            {0,1,0,1,0}};//表示方式:第一个为标号1与本身为0,第一行第二个表示标号1与标号2之间有联系,所以为1,没有连接就为0
    Combineproblem p;
    p=new Hamilton(a,5,1);//5个标号点,从标号1开始出发
    General.backtrack(p);
}
}
 

输出结果:

1->2->5->4->3->1
1->3->2->5->4->1
1->3->4->5->2->1
1->4->5->2->3->1

猜你喜欢

转载自blog.csdn.net/weixin_39653545/article/details/82931915