推销员路径问题-动态规划问题

推销员最优路径问题

  1. 前言

推销员路径问题属于无向图的Hamilton cycle 问题,与Hamilton问题不同的是,推销员路径一定存在从起点出发,路径每个城市一次且仅有一次,最后回到起点城市的最短路径。问题可以归纳为,求解从出发点到其它各个顶点(不包含出发点)的最短距离min_distance, 然后计算上末端顶点至出发点的距离。

  1. 问题分析

在这里插入图片描述

把问题分割为两部分,集合一为当前的城市编号,集合二为已经过的城市(1次且仅1次)集合,DP[current][visited cities collections]表示经过访问过的城市以后,到达当前城市的距离,当前经过的城市可以用某个状态整数表示,例如0011表示经过了城市0和城市1,同理1001表示经过城市3和城市0,它表示已经访问的城市集合,如果整数中某位上为1,那么代表此城市已访问,所有由1组成的位数表示已经访问的城市的集合。

在这里插入图片描述

状态转移方程可以表示为:
d p [ i ] [ v i s i t e d   s e t s ] = m i n { c [ i ] [ k ] + d p [ k ] [ v i s i t e d   s e t s   w i t h o u t   k ] } ; dp[i][visited\ sets]=min\{c[i][k]+dp[k][visited\ sets\ without\ k]\}; dp[i][visited sets]=min{c[i][k]+dp[k][visited sets without k]};
具体状态如上图所示。

  1. 问题求解

a.) 头文件定义

其中函数void tsp_path(int matrix[N][N], int memo[N][1 << N], int *tour, int n, int start)的matrix数组表示无向图,它的值表示两个城市之间的所产生的的费用,由于地理和交通影响,一般情况下,A->B和B->A的之间的费用并不严格相等,数组memo表示dp数组,第一个N代表元素总数,就本问题而言代表N个城市,后面1<<N代表每个城市所对应的状态,由于每个城市都有两个状态,所以总的状态为2的N指数数字。

函数void tsp_setup(int matrix[N][N], int memo[N][1 << N], int n, int start)对DP数组进行初始化,默认城市0(A)为出发城市,假定只有4个城市A,B,C,D;此时有

DP[B][0011]=matrix[A][B]

DP[C][0101]=matrix[A][C]

DP[D][1001]=matrix[A][D]

函数void tsp_solve(int matrix[N][N], int memo[N][1 << N], int n, int start) 是本问题的主要处理函数,它的处理流程为,对visited sets状态进行枚举,然后判断start, end以及next是否在这个状态当中,如果在状态当中,那么就根据大小关系求出next 的对应当前状态下的最小值。

/**
 * @file tsp_problem.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-03-05
 * 
 * @copyright Copyright (c) 2023
 * 
 */

#ifndef TSP_PROBLEM_H
#define TSP_PROBLEM_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define N 4
#define INFINITY 99999

/**
 * @brief find the minimum cost path from start city to start city
 * go through each city only once
 * @param matrix Matrix graph
 * @param memo  Memo to keep record of partial completed tour of city
 * @param tour  Tour path
 * @param n Number of city
 * @param start Start city index
 */
void tsp_path(int matrix[N][N], int memo[N][1 << N], int *tour, int n, int start);

/**
 * @brief Set up the two city minimum cost between each two-cities
 * 
 * @param matrix Matrix graph with adjacent matrix representation
 * @param memo Memo arary with (N*2N) space complexity
 * @param n Number of city in the graph
 * @param start Start city index
 */
void tsp_setup(int matrix[N][N], int memo[N][1 << N], int n, int start);

/**
 * @brief Set up the two city minimum cost between each two-cities
 *
 * @param matrix Matrix graph with adjacent matrix representation
 * @param memo Memo arary with (N*2N) space complexity
 * @param n Number of city in the graph
 * @param start Start city index
 */
void tsp_solve(int matrix[N][N], int memo[N][1 << N], int n, int start);

/**
 * @brief Generate all bit sets of size(n) with r bits set to 1
 * 
 * @param subset Subset collections
 * @param num_subset Number of subset
 * @param r r bits will be set to 1
 * @param n Total number of bit set size
 */
void tsp_combination(int **subset,int *num_subset, int r, int n);

/**
 * @brief Use backtrack method to find all bit sets of n with r bits set to 1
 *
 * @param set Basic number with 0
 * @param at  Start location 
 * @param subset Subset collections
 * @param num_subset Number of subset
 * @param r r bits will be set to 1
 * @param n Total number of bit set size
 */
void combination(int *set, int at,int **subset, int *num_subset, int r, int n);


/**
 * @brief Check if i had been covered in the subset
 * 
 * @param i ith element
 * @param subset Subset state
 * @return true -Return true if not included in the subset
 * @return false -Return false if included in the subset
 */
bool not_in(int i, int subset);

/**
 * @brief Return the minimum cost from the path
 *
 * @param matrix Matrix graph with adjacent matrix representation
 * @param memo Memo arary with (N*2N) space complexity
 * @param n Number of city in the graph
 * @param start Start city index
 * @return int -Return minimum cost of path
 */
int find_minimum_cost(int matrix[N][N], int memo[N][1 << N], int n, int start);

/**
 * @brief Return the optimal tour from the memo array list
 *
 * @param matrix Matrix graph with adjacent matrix representation
 * @param memo Memo arary with (N*2N) space complexity
 * @param tour Tour array list
 * @param n Number of city in the graph
 * @param start Start city index
 * @return int -Return minimum cost of path
 */
void find_optimal_tour(int matrix[N][N], int memo[N][1 << N], int *tour, int n, int start);

int fac(int n);

#endif

b) 函数实现

/**
 * @file tsp_problem.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-03-05
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef TSP_PROBLEM_C
#define TSP_PROBLEM_C
#include "tsp_problem.h"

void tsp_path(int matrix[N][N], int memo[N][1 << N], int *tour, int n, int start)
{
    int min_cost;
    tsp_setup(matrix,memo,n,start);
    tsp_solve(matrix,memo,n,start);
    min_cost=find_minimum_cost(matrix,memo,n,start);
    find_optimal_tour(matrix,memo,tour,n,start);
}

void tsp_setup(int matrix[N][N], int memo[N][1 << N], int n, int start)
{
    int i;

    for(i=0;i<n;i++)
    {
        if(i!=start)
        {
            memo[i][(1 << i) | (1 << start)] = matrix[start][i];
            //memo[i][3] = 1;
        }
    }
}

void tsp_solve(int matrix[N][N], int memo[N][1 << N], int n, int start)
{
    // void tsp_combination(int **subset,int *num_subset, int r, int n);
    int r;
    int i;
    int next;
    int end;  //work as the middle element
    int min_cost;
    int *subset;
    int num_subset=0;
    int state;

    for(r=3;r<=N;r++)
    {
        tsp_combination(&subset,&num_subset,r,n);

        for(i=0;i<num_subset;i++)
        {
           for(next=0;next<N;next++)
            {
                if(next!=start && !not_in(next,subset[i]))
                {
                    min_cost = INFINITY;
                    state=(subset[i])^(1<<next);
                    for(end=0;end<N;end++)
                    {
                        if (end != start && end != next && !not_in(end, subset[i]))
                        {
                            if((memo[end][state]+matrix[end][next])<min_cost)
                            {
                                min_cost = memo[end][state] + matrix[end][next];
                            }
                        }
                    }

                    memo[next][subset[i]] = min_cost;
                }
            }
        }

    }
}

void tsp_combination(int **subset, int *num_subset, int r, int n)
{
    int num;
    int set;
    *num_subset=fac(n)/(fac(n-r)*fac(r));
    *subset=(int *)malloc(sizeof(int)*(*num_subset));
    num=0;
    set =0;


    combination(&set,0,subset,&num,r,n);
}

void combination(int *set, int at, int **subset, int *num_subset, int r, int n)
{
    int i;

    if(r==0)
    {
        (*subset)[*num_subset]=*set;
        (*num_subset)++;
    }
    else
    {
        for (i = at; i < n; i++)
        {
            (*set) = (*set) | (1 << i);
            combination(set, i + 1, subset, num_subset, r - 1, n);
            (*set) = (*set)^(1 << i);
        }
    }
}

bool not_in(int i, int subset)
{
    return (((1<<i) & subset)==0);
}

int find_minimum_cost(int matrix[N][N], int memo[N][1 << N], int n, int start)
{
    int END_STATE=(1<<N)-1;
    int i;
    int min_cost=INFINITY;

    for(i=0;i<n;i++)
    {
        if(i!=start)
        {
            if((memo[i][END_STATE]+matrix[i][start])<min_cost)
            {
                min_cost = memo[i][END_STATE] + matrix[i][start];
            }
        }
    }

    return min_cost;
}

void find_optimal_tour(int matrix[N][N], int memo[N][1 << N], int *tour, int n, int start)
{
    int last_index;
    int index;
    int i;
    int j;
    int end_state=(1<<N)-1;

    last_index=start;

    for(i=N-1;i>=1;i--)
    {
        index=-1;
        for(j=0;j<N;j++)
        {
            if(j!=start && !not_in(j,end_state))
            {
                if(index==-1)
                {
                    index=j;
                }

                if((memo[j][end_state]+matrix[j][last_index])<(memo[index][end_state]+matrix[index][last_index]))
                {
                    index=j;
                }
            }
        }

        tour[i]=index;
        end_state=(end_state ^ (1<<index));
        last_index=index;
    }

    tour[0]=tour[N]=start;

    return;
}

int fac(int n)
{
    if(n<0)
    {
        return 0;
    }
    else if(n==0 || n==1)
    {
        return 1;
    }
    else
    {
        return n*fac(n-1);
    }
}

#endif

c) 函数测试

/**
 * @file tsp_problem_main.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-03-06
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef TSP_PROBLEM_MAIN_C
#define TSP_PROBLEM_MAIN_C
#include "tsp_problem.c"
// void tsp_path(int **matrix, int **memo, int *tour, int n, int start)

int main(void)
{
    int matrix[N][N];
    int memo[N][1<<N];
    int tour[N+1];
    int n;
    int start;

    memset(matrix,0,sizeof(matrix));
    memset(memo,0,sizeof(memo));
    matrix[0][1]=4;
    matrix[0][2] = 1;
    matrix[0][3] = 9;

    matrix[1][0] = 3;
    matrix[1][2] = 6;
    matrix[1][3] = 11;

    matrix[2][0] = 4;
    matrix[2][1] = 1;
    matrix[2][3] = 2;

    matrix[3][0] = 6;
    matrix[3][1] = 5;
    matrix[3][2] = -4;
    n=N;
    start=0;

    tsp_path(matrix,memo,tour,n,start);
    getchar();
    return EXIT_SUCCESS;
}

#endif

  1. 总结

学习到目前位置,对动态规划DP问题,很多时候感觉力不从心,无从下手,尤其是变化莫测的DP数组,更是增加了理解的难度,在这里感觉数学的思维特别重要,尤其是对于DP状态方程的撰写。

参考文献:

  1. 《Traveling Salesman Problem》 by William Fiset
  2. (2条消息) TSP(旅行者问题)——动态规划详解_计算机实务题 旅行家问题_JoeKwok的博客-CSDN博客
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值