精华内容
下载资源
问答
  • 对于TSP旅行商问题,我们做的最多的也就是求最短回路了,那么对于一个数据量适中的图来说,一般的dfs方法即可求解,在这里,我应用dfs的思想来实现此问题,而关键之处在于对矩阵的改进,这样的操作可以使得应用搜索...
    对于TSP旅行商问题,我们做的最多的也就是求最短回路了,那么对于一个数据量适中的图来说,一般的dfs方法即可求解,在这里,我应用dfs的思想来实现此问题,而关键之处在于对矩阵的改进,这样的操作可以使得应用搜索思想求TSP问题时,效率有显著的提高。


    对于矩阵的改进,我们对矩阵的处理是,每一行减去所在行的最小值,每一列减去所在列的最小值,并把这些最小值加到结果sum中,这样的操作是将矩阵稀疏化的改进(注意,稀疏化后的矩阵并不一定是稀疏矩阵,不要混淆),再在剩下的矩阵里进行dfs搜索,从而降低了搜索空间,搜索出的结果加到sum中,即是最终的结果。注意,改进过的矩阵不可再次进行重复改进,也就是说所有行所有列减去最小值的操作只能做一次,至于为什么,大家可以思考一下,如有问题,欢迎留言。


    附上代码:

    #include<stdio.h>
    #define MAX 0x7fffffff
    int g[16][16],visit[16],n,ans=MAX,count=1,sum=0;
    void dfs(int i,int count,int sum)
    {
        int p;
        if(sum>=ans)return;
        if(count==n)
        {
            sum+=g[i][1];
            ans=ans>sum?sum:ans;
            return;
        }
        for(p=1;p<=n;p++)
        {
            if(!visit[p]&&p!=i)
            {
                visit[i]=1;
                dfs(p,count+1,sum+g[i][p]);
                visit[i]=0;
            }
        }
    }
    int main()
    {
        int i,j,min;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            min=MAX;
            for(j=1;j<=n;j++)
            {
                scanf("%d",&g[i][j]);
                if(j!=i&&min>g[i][j])min=g[i][j];
            }
            if(min!=MAX)
            {
                sum+=min;
                for(j=1;j<=n;j++)if(j!=i)g[i][j]-=min;
            }
        }
        for(j=1;j<=n;j++)
        {
            min=MAX;
            for(i=1;i<=n;i++)if(i!=j&&min>g[i][j])min=g[i][j];
            if(min!=MAX)
            {
                sum+=min;
                for(i=1;i<=n;i++)if(i!=j)g[i][j]-=min;
            }
        }
        visit[1]=1;
        dfs(1,1,sum);
        printf("%d\n",ans);
        return 0;
    }


    展开全文
  • C++ 最短哈米尔顿回路问题 种子产生随机数,运用了递归调用算法
  • 最短哈密顿回路

    2019-10-15 14:32:40
    哈密顿回路: 起点和终点相同的哈密顿通路(哈密顿环) 思路: 即旅行商问题 任取一个点作为起点,dfs优先走编号小的点,搜完n个点后判断终点和起点是否相连 据说还可以状压dp、模拟退火 code(dfs): //...

    题意:

    给定无向图
    求边权和最小的哈密顿环(字典序尽量小)
    输出路径

    哈密顿通路:
    经过图中每个节点一次且仅一次的通路  
    哈密顿回路:
    起点和终点相同的哈密顿通路(哈密顿环)

    思路:

    即旅行商问题

    dfs写的
    任取一个点作为起点,dfs优先走编号小的点,搜完n个点后判断终点和起点是否相连

    据说还可以状压dp、模拟退火

    code(dfs):

    //https://www.luogu.org/problem/U71819
    //题意:n个点m条边,求出权值最小的哈密顿回路并输出(字典序尽量小)
    #include<cstring>
    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int maxm=1e3+5;
    const int inf=1e9;
    int g[maxm][maxm];
    int mark[maxm];
    int vis[maxm];
    int res[maxm];
    int n,m;
    int ans;
    int st;
    void dfs(int x,int tot,int sum){
        vis[tot]=x;
        if(tot==n){
            if(g[x][st]!=inf&&sum+g[x][st]<ans){
                ans=sum+g[x][st];
                for(int i=1;i<=n;i++){//copy
                    res[i]=vis[i];
                }
            }
            return ;
        }
        mark[x]=1;
        for(int i=1;i<=n;i++){
            if(g[x][i]!=inf&&!mark[i]){//先判断mark有一个点会tle
                dfs(i,tot+1,sum+g[x][i]);
            }
        }
        mark[x]=0;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){//init
            for(int j=1;j<=n;j++){
                g[i][j]=inf;
            }
        }
        for(int i=1;i<=m;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            g[a][b]=g[b][a]=min(g[a][b],c);
        }
        st=1;
        ans=inf;
        dfs(1,1,0);
        if(ans==inf){
            puts("No Solution!");
        }else{
            for(int i=1;i<=n;i++){
                printf("%d-",res[i]);
            }
            printf("%d\n",st);
        }
        return 0;
    }
    
    展开全文
  • 最短哈密顿回路(旅行商问题

    千次阅读 2018-04-20 13:49:13
    哈密顿回路:不重复地经过每个点,并最终能回到起始点的回路 有别于欧拉回路:不重复经过每条边的回路 ...旅行商问题:求一条经过图中所有点且边权和最小的回路。 以下解法: 模拟退火 状压dp dfs ...

    哈密顿回路:不重复地经过每个,并最终能回到起始点的回路
    有别于欧拉回路:不重复经过每条的回路
    哈密顿回路是点遍历
    旅行商问题:求一条经过图中所有点且边权和最小的回路。
    以下解法:

    • 模拟退火
    • 状压dp
    • dfs
    展开全文
  • 最短路径问题

    2020-08-05 19:43:08
    问题会很复杂,有四种解决方法: 一、Floyed-Warshall算法(O(n^3))  最简单最直接的算法,时间复杂度最高,但也是最万能的算法。能够处理出现负边权的情况,但不能处理存在负权回路(负环)的情况(即某个环的...

    有些时候需要求一个图中两点间的最短路径,在不带边权值时一般是求解最短(长)路径长度,带边权值时可能求结最短(长)路径长度,还可能求解最小(大)边权值和,而有时边权值还可能为负。问题会很复杂,有四种解决方法:
    一、Floyed-Warshall算法(O(n^3))
      最简单最直接的算法,时间复杂度最高,但也是最万能的算法。能够处理出现负边权的情况,但不能处理存在负权回路(负环)的情况(即某个环的总权值是负值)。
      方法就是通过建立另一个数组直接记录两点间的路径,逐步更新以得到最短路径。具体方法是遍历两点间的点k作为中点,然后向两侧扩展i、j,直到得到两点,最终的结果就是最短路径。
      基本代码:(a[][]为求解的图,dis[][]为最短路径)
      其中准备工作中需要将图a[][]中的边即直接相连的点初始化到dis[][]中。特殊题目中,可以通过设置无意义的值标记非直接相连的点,也可以新建立数组表示,还可以访问a[][]解决。

    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j])
            dis[i][j]=dis[i][j]||(dis[i][k]+dis[k][j])//判断两点是否相通
        }
    


      结果自然就是dis[x][z],(x,z是最短路径的起点和终点)。
    二、Dijkstra算法(O(n^2))
      用以计算从一个点到其它所有点的最短路径,一种单源最短路径算法。其实就是找到一个点,由这个点一步一步拓展路径求解,所以它的处理方法中会逐渐沿着多条通路计算路径长度,最终得到最短的到达终点路径。不过这个方法不能解决存在负边权值的情况。
      具体方法:选定一个起点,一步一步寻找最短的路径所能到达的下一个点,记录当前能够到达的点和路径长度(或权值),然后更新所有剩余点可能的最短路径,并对每一个已经确定路径的点标记前一个顶点。直到找到题目要求的终点或者遍历完图,得到答案。应该建立两个数组,一个记录当前路径长度对应的顶点(或包含长度),另一个记录顶点是否被遍历,还可以建立一个记录前驱顶点的数组。
      基本代码:(a[][]为求解的图,dis[]为最短路径长度,b[]记录顶点是否被遍历,pre[]为路径某结点的前驱结点)
      准备工作,起点为x时将dis[x]和pre[x]赋值0,而终点z的dis[z]赋值无穷大数,b[]数组初始化0表示未遍历,,当前中点为y。

    	for(int o=1;o<n;o++)
        {
            for(int i=1;i<=n;i++)
            {
                if(!b[i]&&(dis[i]<minn))
                {
                    minn=dis[i];
                    y=j;
                }
            }
            if(y==0) break;
            b[y]=1;
            for(int i=1;i<=n;i++)
            {
                if(dis[i]+a[y][i]<dis[i])
                {
                    dis[i]=dis[y]+a[y][i];
                    pre[i]=y;
                }
            }
        }
    


      其结果就是dis[z],若想找出最短路径,通过pre[z]寻找即可。
    三、Bellman-Ford算法(O(nm)(n为顶点数,m为边数))
      简称Ford算法。也是计算从一个点到其它所有点的最短路径,也是一种单源最短路径算法。不过,它不再是通过枚举点寻找最短路径,而是枚举边。它相较于Dijkstra算法的优点是能够处理存在负权值的情况,但仍不能处理存在负权回路(负环)的情况。
      具体方法:它的实现和Dijkstra算法基本类似,只是中间稍有区别。枚举的符合条件的边自然是能够连接中间点和当前最短路径的点,而边的长度(或权值)会被记录,所以这种期情况下其实对应的图应该用数组模拟邻接表存储或者我所谓的模型表示法,即用结构体存储边的信息。
      基本代码:(a[]表示求解的图,dis[]为最短路径,pre[]为前驱,x为起点,y为中间点,z为终点)
      准备工作,将dis[x]和pre[x]赋值0,而终点z的dis[z]赋值无穷大数。l,r代表左右端点,len表示长度。

    	for(int o=1;o<n;o++)
        {
            for(int i=1;i<=m;i++)
            {
                if(dis[a[i].l]+a[i].len<dis[a[i].r])
                {
                    dis[a[i].r]=dis[a[i].l]+a[i].len;
                    pre[a[i].r]=a[i].l;
                }
            }
        }
    


      其结果也是dis[z],也可通过pre[z]寻找找出最短路径。这样做的优点是不需要再单独找中点然后更新其它点了,而是直接更新最短路径。
    四、SPFA算法(O(mk)(m是边数,k是个常数,平均值为2))
      实则是Ford算法利用队列进行的优化,但SPFA的优点在于它可以判断负环。形式上确实和广搜很像,但区别是广搜只是用来遍历图的所有点或边,而不是寻找路径,所以不会出现同一个点还要遍历多次的情况,而寻找最短路径不同,它还有可能经过同一个点不止一次,区别在此。
      具体方法:初始时将起点加入队列,之后是从队列取出一个元素,再修改所有其它不在队列里面的与该点相邻的点,修改后将对应的点放入队列,直到队列为空结束。而如果单个点进队或出队次数超过n-1次,说明存在负环,无法求得最短路径。
      基本代码:(a[]表示求解的图,dis[]为最短路径,pre[]为前驱,b[]表示是否在队列中,aans暂时存储从队列中取出的中间点)
      准备工作,b[]清零,dis[1]=0且dis[]的其它元素赋值无穷大。

        q.push(x);
        for(;q.size();)
        {
            aans=q.front();
            q.pop();
            b[aans]=0;
            for(int i=1;i<=m;i++)
            {
                if(a[i].l==aans)
                {
                    if(dis[a[i].l]+a[i].len<dis[a[i].r])
                    {
                        dis[a[i].r]=dis[a[i].l]+a[i].len;
                        pre[a[i].r]=a[i].l;
                        if(!b[a[i].r])
                        {
                            b[a[i].r]=1;
                            q.push(a[i].r);
                        }
                    }
                }
            }
        }
    

    结果自然也是dis[z],同样可以通过pre[z]寻找最短路径。至于要判断是否有负环,那只能再多一个数组判断了。

    展开全文
  • 最短路径问题 一、题目要求: 二、子问题(1)哈密顿回路 1.问题建模描述 给定一个n个结点,m条有向边(边权为正)的图,求出一条路径满足如下条件: 条件一:该路径可以从任意节点开始,不过起点和终点必须...
  • N个城市,要求走一条最短回路 问题特殊之处在于距离的定义。 在这种情况下,两个城市组成一个矩形,如果矩形内包含其它点,根据贪心法,肯定不能直接从左上角走到右下角,那样会白白错过一些城市。 import java....
  • 图论最短路径问题

    2020-08-21 18:04:24
    图的基本概念 ...不支持含有负权回路的图 弗洛伊德算法 (1)如果某个节点(例如点8)位于从起点0到终点4的最短路径上,那么: 从0到4的最短路径的距离=从0到8的最短路径的距离+从8到4的...
  • 2.适用范围:数据范围小的情况下可用于计算所有点间的最短路,且可以解决带有负权边的图,但不能用于解决负权环(带有负权边的回路问题。 3.思想:中转。比较 点i和点j间的现有最短路径 与 点i通过点k中转到达点k...
  • 数学建模之图论最短路径问题

    千次阅读 2020-07-10 21:44:07
    图论基本概念及如何作图 无向图的权重邻接矩阵 有向图的权重邻接矩阵 ...不能处理负权重问题; 解决方法:贝尔曼福特算法 贝尔曼福特算法 负权回路: matlab计算最短路径: [P,d] = shortestpath(G
  • 1.先确认一个点查找他连接的最短路径的顶点,然后记录下该顶点,然后查到这两个顶点连接最短路径的顶点,不能出现回路,然后在判断这个三个依次累计,直到所有顶点全部连接 代码: package ...
  • Floyd-Warshall算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。 Floyd-Warshall算法的时间复杂度为O(N^3),空间...
  • 德国120个城市的最短旅行商回路

    千次阅读 2015-03-10 19:47:47
    德国120个城市的最短旅行商回路TSP问题
  • 最短路径问题---Floyd算法详解

    千次阅读 2019-03-04 15:35:41
    弗洛伊德算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。 2. 算法的思路 通过Floyd计算图G=(V,E)中各个顶点...
  • 弗洛伊德算法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或有向图或负权(但不可存在负权回路)的最短路径问题,同时也被用于计算有向图的传递闭包。 2.基本思想: 对于从vi到vj的弧,进行n次试探:...
  • 注意,最短路径问题实际上均不允许有负值回路(当然是从源点可达的),因为这时不存在最短路径。总会有更短的办法-多绕负边回路走几趟就是了。   首先介绍一下松弛技术(Relaxation) 对每个顶点,都设置一个...
  • 在某些单源最短路径问题中,可能存在权为负的边。如果图G(V,E)不包含由源s可达的负权回路,则对所有v∈Vs,最短路径的权的定义&(s,v)依然正确,即使它是一个负值也是如此。但如果存在一个从s可达的负权回路最短...
  • 最短路径问题—Bellman-Ford算法 (原题传送) Bellman-Ford算法: 简称Ford(福特)算法 同样是用来计算从一个点到其他所有点的最短路径的算法,也是一种单源最短路径算法。 优点:能够处理存在负边权的情况,但无法...
  • 多源最短路径问题是指求解在**有向图**中**任意两点间**的最短路径,时间复杂度O(N3)也可以处理带负权边的图(无负权回路)。 代码如下: #include <stdio.h> int main() { int i,j,k,t1,t2,t3,n,m; int ...
  • 今天我们来学习Bellman-Ford算法,它是一种单源的可带负权边最短路径算法,但它不能算出含负权回路的图(PS:负权回路指起点和终点相同的总权重为负的路径,其实就是一个环的总代价为负),因为本身每多走一次负...
  • 注意,最短路径问题实际上均不允许有负值回路(当然是从源点可达的),因为这时不存在最短路径。总会有更短的办法-多绕负边回路走几趟就是了。 首先介绍一下松弛技术(Relaxation)对每个顶点,都设置一个属性d[v],...
  • Dijkstra算法也算是一个入门级别的算法了,这里的代码用来解决单起点最短路径问题嗷,其他的原理和正确性证明移步其他qaq,不多说,上代码 #Author:BeiZhai #2020/10/22 #Dijkstra算法,一开始还搞错了呜呜呜 #...
  • 简要:Bellman-Ford算法计算的仍然是从一个点到其他所有点的最短路径算法,其时间复杂度是O(NE),N表示点数,E表示边数,不难看出,当一个图稍微稠密一点,边的数量会超过点数那么实际上效率是低于Dijkstra算法的。...
  • 第八讲:图论最短路径问题 图的基本概念 在线做图 Matlab帮我们作图 无向图的权重邻接矩阵 有向图的权重邻接矩阵 迪杰斯特拉算法 玩一个APP 看视频演示 步骤演示 迪杰斯特拉算法的...
  • 要求你写一个程序,判断这个有向图中是否存在负权回路。如果从一个点沿着某条路径出发,又回到了自己,而且所经过的边上的权和小于000,就说这条路是一个负权回路。如果存在负权回路,只输出一行−1−1−1;如果不...
  • 24.2-4:给出一个高效算法来统计邮箱无回路图中的全部路径数。分析所给出的算法。24.3-6:设G=(V,E)为带权有向图,权函数W: E-> {0,1,....,W},其中W为某非负整数。修改Dijkstra算法,以使其计算从指定源点s的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 515
精华内容 206
关键字:

最短回路问题