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;、

    就可以。

    输出;

  • 相关阅读:
    .NET定时任务执行管理器开源组件–FluentScheduler
    ASP.NET MVC 使用 FluentScheduler 定时器计划任务
    Windows 2008 IIS7.5中创建独立账号的FTP站点图文教程
    除非Microsoft FTP 服务(FTPSVC)正在运行,否则无法启动FTP站点。服务目前已停止
    Web API--自定义异常结果的处理
    C#怎么遍历一个对象里面的全部属性?
    WebApi 接口参数不再困惑:传参详解
    C#进阶系列——WebApi 接口测试工具:WebApiTestClient
    WebApi安全性 使用TOKEN+签名验证
    ASP.NET(C#) Web Api通过文件流下载文件到本地实例
  • 原文地址:https://www.cnblogs.com/youxin/p/3272659.html
Copyright © 2011-2022 走看看