回溯法求解哈密顿回路问题

假设图中有n个顶点1,2,3,4,5,6,7

用x[i] 存储问题的解。

x[1]存储初始点,x[2]存储第二个点。以此类推。

bool b[n+1][n+1] 存储图的邻接矩阵。

约束条件:

xi!=xj          0<=i,j<=n i不等于j

 b[xi-1][xi]=true 当前点与前一个点邻接

特别地,当i=n时还要满足b[1][n]=true;

代码:

#include <iostream>   
#include<cstdio>
using namespace std;  
bool b[100][100]; //图的邻接矩阵 

bool check(int x[],int n, int k)
{
    
    for(int i=1;i<k;i++)
    {
        if(x[i]==x[k] )
            return false;
    }
    int tmp1,tmp2;
    tmp1=x[k-1],tmp2=x[k];
    if(b[tmp1][tmp2]) //if(b[k-1][k])错误
    {
        if(k==n)
            return b[1][tmp2]; //k等于n要单独考虑

        return true;
    }
    else
        return false;
}


void hamilton(int x[],int n,int k)
{
    for(int i=1;i<=n;i++)
    {
        x[k]=i;
        if(check(x,n,k))
        {
            if(k==n)
            {
                for(int m=1;m<=n;m++) cout<<x[m]<<ends;
                cout<<endl;
                 
            }
            else
            {
                hamilton(x,n,k+1);
            }
        }
    }
}
void hamilton2(int x[],int n)
{
    x[2]=0;
    int k=2;
    while(k>1)
    {
        x[k]+=1;
        while(x[k]<=n && !check(x,n,k) )
        {
            x[k]+=1;
        }
        if(x[k]<=n)
        {
            if(k==n)
            {
                for(int m=1;m<=n;m++) cout<<x[m]<<ends;
                cout<<endl;
                x[k]=0;
                k--;
            }
            else
            {
                k++;
                x[k]=0;
            }
        }
        else
        {
            x[k]=0;
            k--;
        }
    }
}
 
int main()
{
    freopen("hamilton.txt","r",stdin);
    int n;
    cout<<"输入顶点数"<<endl;
    cin>>n;

    int *x=new int[n+1];

    int edges;
    cout<<"边数"<<endl;
    cin>>edges;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            {
                if(i==j) b[i][j]=true;
                else b[i][j]=false;
        }

    int start,end;
    cout<<"属于边d的起点和终点"<<endl;
    for(int i=1;i<=edges;i++)
    {
        cin>>start>>end;

        b[start][end]=true;
        b[end][start]=true;
    }
    x[1]=1;
    //hamilton(x,n,2);
    hamilton2(x,n);
}
         

用递归和不用递归结果都一样。

注意划红线 部分;

int k=2;
    while(k>1)
为什么k>1。
第一个点x[1]=1;已经确认了,我们从第二个点开始。
这跟k=1; k>0是一样的道理

输入:

5

8

1 2 
1 4
2 4
2 3
4 5
3 5
3 4
2 5


输出:

上面代码中的第一个点默认x[1]=1;就是说我们已经规定了起点,如果我们不规定起点,找出所有的哈密顿回路,怎么办?

调用之前不用写x[1]=1。

把:

    x[2]=0;
    int k=2;
    while(k>1)
    {
        x[k]+=1;

改为

    x[1]=0;
    int k=1;
    while(k>0)
    {
        x[k]+=1;

就可以了吗?不可以,运行就报错。

原因是什么,是我们的check函数:

bool check2(int x[],int n, int k)
{

    for(int i=1;i<k;i++)
    {
        if(x[i]==x[k] )
            return false;
    }
    int tmp1,tmp2;
    tmp1=x[k-1],tmp2=x[k];
    if(b[tmp1][tmp2]) //if(b[k-1][k])错误
    {

当k=1时x[0]是一个随机的数,我们没有赋值。这样b[tmp1][tmp2]必然有问题,我们只要加上k是否为1的判断就可以了。

在函数最前面加上;

if(k==1) return true;、

就可以。

输出;

原文地址:https://www.cnblogs.com/youxin/p/3272659.html