zoukankan      html  css  js  c++  java
  • 使用C++TR1实现物流配送问题的简单模拟

       物流配送问题是典型的NP完全问题,寻找求解该问题的高效准确的算法一直以来都是研究热点。我在这里不是讨论解决该问题的具体算法,而是简单介绍一下C++98的一个功能强大扩展--TR1
      TR1Technical Report 1的简称,它原本是标准委员会内部的一个名称。它是在1998年标准委员会提出C++ Standard(就是我们说的"标准C++")之后 委员会拟定的下一个版本的C++ Standard应该具有的功能的一份描述。它仅是一份文档,本身并没有做出具体实现,但其中列出的这些实现很值得我们去了解。关于TR1Effective C++3e)》Item54有比较详细的介绍,这里不多说了。
      支持TR1的开发环境有:
            gcc4.*.*(gcc4.0及以后的版本)
          MSVC2008(vs2008及以后版本)

    问题描述:   
        针对一般的分销系统,即系统由分销中心(DC),多个零售商组成,该系统的运营成本主要由运输成本与库存成本构成。分销中心用自己的车辆为各零售商供货,而分销中心由制造商直接供货,假设零售商处的顾客需求是随机的且服从一定的概率分布,不同零售商之间以及同一零售商不同时期之间的需求是独立的。一般DC与零售商均采用周期补货策略,补货时刻为周期末,DC的一个补货周期一般包含多个零售商的补货周期。现考虑只有一个分销中心和30个零售商组成的分销系统,配送货物为单一产品。试就顾客需求服从参数为6Possion分布,销售中心位置为(0,0),30个零售商的位置可在[-200,200]‰[-200,200]的平面上随机产生得到的分销系统的运输、配送策略建立数学模型,并以题目中提供的部分数据为基础,进行数据模拟。

    程序实现:

    #include <cstdio>
      #include <iostream>
      #include <fstream>
      #include <set>
      #include <vector>
      #include <random>
      using namespace std;
      using namespace std::tr1;
      
      #define PRINT_RES
      #define PRINT_STEP
      ofstream fout("res.txt");
      
      int nTests = 500; // 存放模拟次数
      const int N = 30; // 零售商
      const int Q = 18; // 车的载重量
      
      typedef double require_t;
      double x[N+1], y[N+1]; // 零售商的坐标
      double W[N+1][N+1];        // 带权邻接矩阵
      require_t q[N+1];      // 零售商处的客户需求
      
      inline double squre(double x) {    return x*x; }
      int main()
      {
         random_device rd;   // 随机数引擎
         mt19937 gen(rd());  // 随机数算法
         uniform_int<double> uniform(-200, 200); // 均匀分布随机数发生器
         poisson_distribution<double> poisson(6.0); // 泊松分布随机数发生器
         
         x[0] = y[0] = 0.0;
         double res=0;
         
         cout<<"请输入试验次数:";
         cin >> nTests; // 输入模拟次数
         for(int t=1; t<=nTests; t++) {
             
             // 生成随机数:
             int rc1 = 1, rc2 = 1;;
             set<double> sreq;
             set< pair<double, double> > pset;
             while( rc1 <= N || rc2 <= N ) {
                 // 零售商位置 服从均匀分布
                 x[rc1] = uniform(gen);
                 y[rc1] = uniform(gen);
                 if( !(x[rc1] == 0.0 && y[rc1] ==0.0) ) {
                     pset.insert( pair<double, double>( x[rc1], y[rc1] ) );
                     rc1++;
                 }
                 // 客户需求 服从泊松分布
                 q[rc2] = poisson(gen); 
                 if( q[rc2] > 0.0 ) {
                     sreq.insert( q[rc2] );
                     rc2++;
                 }
             }       
             
             // 更新邻接矩阵:
             for(int i=0; i<=N; i++) {
                 for(int j=0; j<=N; j++)  {
                     W[i][j] = sqrt( squre(x[i]-x[j]) + squre(y[i]-y[j]) );
                 }
             }
      
             set<int> V;
             for(int i=1; i<=N; i++) V.insert(i);
             
             /***************************************************************************
              贪婪算法(greedy algorithm)
               时间复杂度:O(n^2*log2(n))
                 Step1: 令S={},u=0, k=1;
                 Step2: 令R(k)={u},Qt=Q;
                 Step3: 构建集合AR(u)={e| e∈A(u)且e∈S,且q(e) < Qt };
                 Step4: 如果AR(u)≠{},则
                             从AR(u)中找到到u的权最小的x,更新R(k),S,Qt,u:
                             R(k)=R(k)∪{x},S=S∪{x},Qt=Qt-q(x),u=x;
                             跳转到(3);
                         否则,继续(5);
                 Step5: 如果S≠V,则k=k+1,u=0转到(2);否则,结束;
             ****************************************************************************/
             // 1.   令S={},u=0, k=1;
             set<int> S;
             int u=0, k=1;       
             vector<int> R[N+1];           
      
             while(1) {
                 // 2.令R(k)={u},Qt=Q;
                 R[k] = vector<int>(1, u); 
                 double Qt = Q;      
                 while(1) {
                     // 3.构建集合AR(u)={e| e∈A(u)且e∈S,且q(e) < Qt }
                     set<int> AR;
                     for(int e=1; e<=N; e++) {
                         if( W[u][e]!=0 && q[e]<Qt && S.count(e)==0 )
                             AR.insert( e );
                     }
                     
                     // 4.从AR(u)中找到到u的权最小的x,更新R(k),S,Qt,u
                     if( AR.size() ) {
                         double minw = 0;
                         int minx=0;
                         set<int>::iterator it=AR.begin();
                         for( ;it != AR.end(); it++ ) 
                         {
                             if( q[*it]/W[u][*it] > minw ) {
                                 minx = *it; 
                             }
                         }                   
                         R[k].push_back( minx );
                         S.insert( minx );
                         Qt -= q[ minx ];
                         u = minx;
                         continue;
                     }
                     else break;
                 }
                 // 5.如果S≠V,则k=k+1,u=0转到(2);否则,结束;
                 if( S != V ) {
                     if( V.size() - S.size() == 1 ) {
                         R[k+1] = vector<int>(2, 0);
                         R[k+1][1] = *V.begin();
                         break;
                     }
                     if( R[k].size()>1 ) k++; 
                     u=0;
                     continue;
                 }
                 else break;
             }
      
             // 计算本次模拟的 运营成本:
             double C=0;
              for(int i=1; i<=N; i++) {
                  if( R[i].size() )  {
                      vector<int>::iterator it=R[i].begin();
                      for( ; it+1!=R[i].end(); it++) {
                          C += W[*it][*(it+1)];
                      }
                      C += W[*it][0];
                  }
              }
             // 打印各次配送的路线:
              printf("\n第%d次模拟...\n", t);
              for(int i=0; i<=N; i++) {
                  if( R[i].size() ) {
                      printf("第%d趟发货:\t", i);
                      //int j=0, sz = R[i].size();
                      vector<int>::iterator it=R[i].begin();
                      for( ; it!=R[i].end(); it++) {
                          printf("%d\t", *it );// printf("(%d,%d)\t", *it, *(it+1) );
                      } // printf("(%d,%d)\t", *it, 0 );
                      printf("\n");
                  }
              }
              printf("运输成本: %g\n", C);
             fout << C << "\n";
             res += C;
         }
         printf("\n模拟次数:%d\n平均运输成本:%g\n", nTests, res/nTests );
         return 0;
      }

     注:以上代码只在vc2008中编译通过,在gcc中编译可能会出现问题(在我的gcc上没有编译成功,好像是gcc实现版的TR1所在的头文件不太一样)。

        这里只用到了TR1的随机数生成工具,它大大超越了rand(),它除了提供正态分布以外,还提供了正态分布、泊松分布、伯努利分布等概率分布,而且使用起来也相当简单。

    这里是关于TR1的一份清单:

    EC++
    Page
    Effective C++, Third Edition
    Name
    TR1 Name Proposal
    Document
    265 Smart Pointers Smart Pointers n1450
    265 tr1::function Polymorphic Function Wrappers n1402
    266 tr1::bind Function Object Binders n1455
    266 Hash Tables Unordered Associative Containers n1456
    266 Regular Expressions Regular Expressions n1429
    266 Tuples Tuple Types n1403 (PDF)
    267 tr1::array Fixed Size Array n1479
    267 tr1::mem_fn Function Template mem_fn n1432
    267 tr1::reference_wrapper Reference Wrappers n1453
    267 Random Number Generation Random Number Generation n1452
    267 Mathematical Special Functions Mathematical Special Functions n1422
    267 C99 Compatibility Extensions C Compatibility n1568
    267 Type Traits Metaprogramming and Type Traits n1424
    267 tr1::result_of Function Return Types n1454


    关于TR1的描述的原始链接:http://www.aristeia.com/EC3E/TR1_info.html

     最新的C++标准已在去年发布,即C++11.

    关于C++11的一份清单(包括C++全部内容):

    C++参考
    C++98,C++03,C++11

    语言

    概念

    实用工具库

    字符串库

    容器库

    array (C++11)  −  vector  −  deque
    list  −  forward_list (C++11)
    set  −  multiset
    map  −  multimap
    unordered_set (C++11)
    unordered_multiset (C++11)
    unordered_map (C++11)
    unordered_multimap (C++11)
    stack  −  queue  −  priority_queue

    算法库

    迭代器库

    数值算法库

    输入/输出库

    本地化库

    正则表达式库 (C++11)

    原子操作库 (C++11)

    线程的支持库 (C++11)

    关于每个内容的详细说明http://www.cplusplus.com/上也有不错的说明(两个网站的内容差不多).原始链接:http://zh.cppreference.com/w/%E9%A6%96%E9%A1%B5

      但目前,支持C++11的编译器并不多,只有:

           gcc 4.7.*

        VC2012 

       C++11有更多更强大、更有趣的内容供我们使用,我们要做的就是去熟悉。


  • 相关阅读:
    思念
    Matlab与C++混合编程,添加OpenCV库
    重新启用此博客
    将博客搬至CSDN
    unity探索者之ILRuntime代码热更新
    unity探索者之UGUI圆形图片组件
    unity探索者之UGUI图片描边
    unity探索者之iOS微信登录、分享
    unity探索者之复制内容到剪贴板
    unity探索者之获取设备当前电量
  • 原文地址:https://www.cnblogs.com/xusw/p/5205869.html
Copyright © 2011-2022 走看看