动态规划货郎担问题

参考http://blog.csdn.net/tianshuai1111/article/details/7535026和《算法设计与分析》这本书

问题描述

        1)货郎担问题提法:有n个城市,用1,2,…,n表示,城i,j之间的距离为dij,有一个货郎从城1出发到其他城市一次且仅一次,最后回到城市1,怎样选择行走路线使总路程最短? 

  

        2)旅行商问题的提法:假设有一个旅行商人要拜访n个城市,他必须选择所要走的路径,路经的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是要求得的路径路程为所有路径之中的最小值。

(特说明这部分我是直接复制 blog.csdn.net/tianshuai1111/article/details/7535026

问题求解

 

  1)动态规划解
  

    例题: 设v1,v2,……..,vn是已知的n个城镇,城镇vi到城镇vj的距离为dij,现求从v1出发,经各城镇一次且仅一次返回v1的最短路程。

  

          分析:设S表示从v1到vi中间所可能经过的城市集合,S实际上是包含除v1和vi两个点之外的其余点的集合,但S中的点的个数要随阶段数改变。

          建模:状态变量(iS表示:从v1点出发,经过S集合中所有点一次最后到达vi。
                      最优指标函数fkiS为从v1出发,经过S集合中所有点一次最后到达vi。
                      决策变量PkiS表示:从v1经k个中间城镇的S集合到vi城镇的最短路线上邻接vi的前一个城镇,则动态规划的顺序递推关系为:

                          fk(i,S)=   min{  fk-1(j,S、{ j }+dji}        j属于S

                         f0(i,空集)=d1i (k=1,2,…,n-1,i=2,3,…n)


          求解:K=0

                             f0(2,空集)=d12=6  
                             f0(3,空集)=d13=7
                             f0(4,空集)=d14=9

                     当k=1时:
                              从城市V1出发,经过1个城镇到达Vi的最短距离为:

f1(2,{ 3 }) = f0 (3,空)+d 32 =7+8=15
f1(2,{ 4 }) = f0 (4,空)+d 42 =9+8=14
f1(3,{ 2 }) = f0 (2,空)+d 23 =6+9=15
f1(3,{ 4 }) = f0 (4,空)+d 43 =9+5=14
f1(4,{ 2 }) = f0 (2,空)+d 24 =6+7=13
f1(4,{ 3 }) = f0 (3,空)+d 34 =7+8=15


  当k=2时,
     
      从城市V1出发,中间经过2个城镇到达Vi的最短距离.

f2(2,{ 3,4 }) = min[ f1(3,{4})+d32,   f1(4,{3})+ d42] 
=min[14+8,15+5]=20
                P2(2,{3,4})=4

f2(3,{ 2,4 })= min[14+9,13+5]=18 
P2(3,{2,4})=4
          
f2(4,{ 2,3})= min[15+7,15+8]=22
P2(4,{2,3})=2

   当k=3:

从城市V1出发,中间经过3个城镇最终回到Vi的最短距离.

  f3(1,{ 2,3,4 })= min[f2(2,{ 3,4 }) + d 21,f2(3,{ 2,4})+ d31,f2(4,{ 2,3 }) + d41]=min[20+8,18+5,22+6]=23

    
P3(1,{2,3,4})=3


逆推回去,货郎的最短路线是1  2  4  3  1,最短距离为23.

(我的代码如下):

#include"stdio.h"
#include <iostream>
#define MAX 10000 //相当于无穷
using namespace std;
int array_cost[4][4]=
{ {MAX,3,6,7},  
    {5,MAX,2,3},  
    {6,4,MAX,2},  
    {3,7,5,MAX}
};  
int flag_Four[4]={1,0,0,0};
int flag=0;           //全局变量
int distance_1=0;
//int min_num=MAX;//这样定义为全局变量是不对的
int DieDai(int num)
{

   if(flag==3)
   {
  return  array_cost[num][0];
   }
       int min_num=MAX;       我一直迷糊这里,最主要是对变量在函数中的作用范围不清晰
                                              为啥min_num不能定义为全局变量,现在心里有数了
       for(int i=0;i<4;i++)
  {
// cout<<i<<"  i:"<<flag_Four[i]<<endl; 
         if(flag_Four[i]!=1&&i!=0)
{
flag_Four[i]=1;
            flag++;
distance_1=array_cost[num][i]+DieDai(i);
            if(distance_1<min_num)
{
      min_num=distance_1;     
  //cout<<min_num<<endl;
}
        flag--;                //这里我们需要还原
                flag_Four[i]=0;//这里我们需要还原
}
  }
      return min_num;
}
void main()
{
     cout<< DieDai(0);
}

下面的程序是参考: http://blog.csdn.net/tianshuai1111/article/details/7535026   直接复制

#include<iostream>  
#include<iomanip>  
using namespace std;  
  
int n;  
int cost[20][20];  
bool done[20]={1};  
int start = 0; //从城市0开始  
 // int mincost=10000;
int imin(int num, int cur)  
{  
    if(num==1) //递归调用的出口  
        return cost[cur][start];  //所有节点的最后一个节点,最后返回 最后一个节点到起点的路径  
  
 int  mincost = 10000;  
    for(int i=0; i<n; i++)  
    {  
        cout<<i<<"  i:"<<done[i]<<endl;   
        if(!done[i] && i!=start) //该结点没加入 且 非起始点   
        {  
            //if(mincost <= cost[cur][i]+cost[i][start])  
            //{  
           //     continue; //其作用为结束本次循环。即跳出循环体中下面尚未执行的语句。区别于break   
           // }  
            done[i] = 1; //递归调用时,防止重复调用  
              
            int value = cost[cur][i] + imin(num-1, i);  
  
            if(mincost > value)  
            {  
                mincost = value;  
cout<<mincost<<endl;
            }  
            done[i] = 0;//本次递归调用完毕,让下次递归调用  
        }  
    }  
    return mincost;  
}  
  
int main()  
{  
//  cin >> n;  
     n=4;  
     int cc[4][4]={{0 ,4, 1, 3},  
               {4 ,0 ,2, 1},  
               {1 ,2 ,0, 5},  
                   {3 ,1, 5, 0}};  
    for(int i=0; i<n; i++)  
    {  
        for(int j=0; j<n; j++)  
        {  
            //cin >> cost[i][j];  
            cost[i][j]=cc[i][j];  
        }  
    }  


    cout << imin(n, start) << endl;  
  
    return 0;  
}  

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值