zoukankan      html  css  js  c++  java
  • 回溯法求解哈密顿回路问题

    假设图中有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;、

    就可以。

    输出;

  • 相关阅读:
    pipelinewise 学习二 创建一个简单的pipeline
    pipelinewise 学习一 docker方式安装
    Supercharging your ETL with Airflow and Singer
    ubuntu中使用 alien安装rpm包
    PipelineWise illustrates the power of Singer
    pipelinewise 基于singer 指南的的数据pipeline 工具
    关于singer elt 的几篇很不错的文章
    npkill 一个方便的npm 包清理工具
    kuma docker-compose 环境试用
    kuma 学习四 策略
  • 原文地址:https://www.cnblogs.com/youxin/p/3272659.html
Copyright © 2011-2022 走看看