代码改变世界

回溯法解哈密顿问题

2012-07-12 17:46  youxin  阅读(1934)  评论(0编辑  收藏  举报

回溯法求解:

    首先把回路中的所有顶点编号初始化为0,然后,把顶点0当做回路中的第0个顶点,即x0=0;搜索与0邻接的编号最小的顶点,作为它的后续顶点,判断是否满足约束条件,是则到达该顶点,x1取值为满足条件的顶点编号,然后再以同样的方式搜索。

 

     假设在搜索过程中已经生成了通路L=x0x1....,xi-1,在继续搜索某个顶点作为通路的xi顶点时,
根据约束条件,在V中选择与xi-1邻接的并且不属于L的编号最小的顶点

  如果搜索成功,则把该顶点作为xi,否则就把L中的xi-1删去(回溯),从xi-1顶点编号加1的位置开始,继续搜索与xi-2相邻接且不属于L的顶点。这个过程一直继续下去。


当搜索到xn-1时,如果xn-1与x0相邻接,就得到了一天hamilton回路,否则把xi-1删去,继续回溯。
最后,在回溯过程中,L中只剩下一个顶点x0,表明不存在哈密顿回路。

 

#include<iostream>
#include<cstdio>
 using namespace std;
 
void hamilton(int **a,int n,int x[])//x[] 存放回路的顶点序号 a不能写成二维数组形式,否则报错:不能从int **转为 int [ ]]

{
    bool *s=new bool[n]; //s记录顶点的使用与否
    for(int i=0;i<n;i++)
    {
        x[i]=-1;
        s[i]=false;
    }
    s[0]=true;
    x[0]=0; //从序号0开始搜索
    int k=1; //初始深度为1,因为有n个节点且第一个节点已给出(k=0),故空间搜索树的深度为n-1(1到n-1)
    while(k>=0) 
    {
        x[k]=x[k]+1;
        while(x[k]<n)
        {
            if((!s[x[k]])&&(a[x[k-1]][x[k]]==1))
            {
                //顶点x[k]未被使用而起与前一节点x[k-1]有连线
                break;
            }

            else 
                x[k]=x[k]+1;
            }
        if(x[k]<n)
        {
            if(k!=n-1) //搜索成功,深度加1
            {
                s[x[k]]=true;
                k=k+1;
            }
            else
                break;
        }
        else
        {
            x[k]=-1;
            k=k-1;
            s[x[k]]=false;
        }
    }
}
 


int main()
{
    int n;
    freopen("货郎担问题42.txt","r",stdin);
    cin>>n;  //顶点数 
    int **a=new int *[n];  
    for(int i=0;i<n;i++)
        a[i]=new int[n];
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            cin>>a[i][j];
    int *x=new int[n];
    hamilton(a,n,x);
    for(int i=0;i<n;i++)
        cout<<x[i]<<ends;
    cout<<endl;

}

 

文件如下:

4
0 0 1 1
1 0 1 1
1 1 0 1

 

输出0 2 1 3