预处理器
关键字
运算符优先级
转义序列
ASCII表
基本类型
物流配送问题是典型的NP完全问题,寻找求解该问题的高效准确的算法一直以来都是研究热点。我在这里不是讨论解决该问题的具体算法,而是简单介绍一下C++98的一个功能强大扩展--TR1。
TR1是Technical Report 1的简称,它原本是标准委员会内部的一个名称。它是在1998年标准委员会提出C++ Standard(就是我们说的"标准C++")之后 委员会拟定的下一个版本的C++ Standard应该具有的功能的一份描述。它仅是一份文档,本身并没有做出具体实现,但其中列出的这些实现很值得我们去了解。关于TR1《Effective C++(3e)》Item54有比较详细的介绍,这里不多说了。
支持TR1的开发环境有:
gcc4.*.*(gcc4.0及以后的版本)
MSVC2008(vs2008及以后版本)
问题描述:
针对一般的分销系统,即系统由分销中心(DC),多个零售商组成,该系统的运营成本主要由运输成本与库存成本构成。分销中心用自己的车辆为各零售商供货,而分销中心由制造商直接供货,假设零售商处的顾客需求是随机的且服从一定的概率分布,不同零售商之间以及同一零售商不同时期之间的需求是独立的。一般DC与零售商均采用周期补货策略,补货时刻为周期末,DC的一个补货周期一般包含多个零售商的补货周期。现考虑只有一个分销中心和30个零售商组成的分销系统,配送货物为单一产品。试就顾客需求服从参数为6的Possion分布,销售中心位置为(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++参考 |
||
语言 预处理器 头 概念 实用工具库 类型的支持 |
字符串库 basic_string 容器库 array (C++11) − vector − deque 算法库 迭代器库 数值算法库 常见的数学函数 |
输入/输出库 basic_streambuf 本地化库 正则表达式库 (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有更多更强大、更有趣的内容供我们使用,我们要做的就是去熟悉。