分支界定法:最大装载问题,获得最优路径(使用FIFO),深刻学习指针的引用的本质
2012-02-11 08:44
337 查看
// 17x4.cpp : Defines the entry point for the console application. // #include "stdafx.h" // 分支界定法:最大装载问题,获得最优路径(使用FIFO),深刻学习指针的引用的本质 #include <iostream.h> #include "lqueue.h" #include "qnode.h" // QNode具有一个QNode *parent, bool LChild, T weight三个属性 // 如果不是叶节点,就加入到Q队列里。新节点是E的孩子。 // E与bestE有区别,一个不带引用,一个带引用,深刻体会QNode<T>*& bestE的使用 template<class T> void AddLiveNode(LinkedQueue<QNode<T>*>& Q, T wt, int i, int n, T bestw, QNode<T> *E, QNode<T>*& bestE, int bestx[], bool ch) { cout << "函数参数QNode<T>*& bestE去掉&,&bestE的地址就变了=" << &bestE << ", bestE="<< bestE << endl; // bestE被不断传进来,传递方式是带引用的指针QNode<T>*& ,所以实际上只有一个,以后就靠它回溯取得最优路径 // 叶节点不需要生成,只要到达了叶节点并且是最大值的那一次,直接记录下bestx = ch;,即0或者1 // 于是只要记录叶节点的parent就可以了,即bestE,它已经在GetMaxLoading里定义,并且是唯一的。然后靠它回溯取得最优路径 // 不是叶节点就也有可能有最大值。但不是叶节点就不必更新bestE和bestx 的值(bestx =true/false都有可能) if (i == n) { // 到达叶节点 if (wt == bestw) { bestE = E; // 迄今的最佳值,而且只在这里有可能被改变。 cout << "adr changed??? &bestE=" << &bestE << ", bestE="<< bestE << endl; bestx = ch; cout << "i=" << i << ", best adr node="<< bestE << endl; } return; } // 只要不是叶子,添加到队列,这样方便由最后记录的那个叶节点来回溯,得到最佳路径 QNode<T> *b; // 每次都新建一个节点,所以多生成了许多QNode节点 b = new QNode<T>; b->weight = wt; // 节点的重量等于路径到当前节点的值 b->parent = E; // b->LChild = ch; // cout << "i=" << i << ", E="<< E << ", adr node="<< b << endl; // 这里队列Q添加的元素比较特殊,具有parent和LChild属性,而以前只是wt的值 Q.Add(b); } // 返回最大装载和最大装载的路径 template<class T> T GetMaxLoading(T w[], T c, int n, int bestx[]) { LinkedQueue<QNode<T>*> Q; // 活结点队列 // 为第一层初始化 Q.Add(0); // 0 变成了层结束的标志 int i = 1; // E-节点的层 T Ew = 0, // E-节点的权重(节点自身与所有祖先的权重的累加) bestw = 0; // 迄今最佳重量 T r = 0; // E-节点时候的所有物品的剩余重量总和 for (int j = 2; j <= n; j++) r += w[i]; // QNode具有一个QNode *parent, bool LChild, T weight三个属性 QNode<T> *E = 0, // 当前E-节点,作为AddLiveNode的参数,作为当前节点的parent。因此首节点的parent为0 *bestE; //迄今最佳E-节点,作为AddLiveNode的参数
/*
4G的内存地址, 系统还要留下一半($80000000 - $FFFFFFFF, 这 2G 是各进程共享的)用作宏观管理;
只给程序 2G(0 - $7FFFFFFF). 就这 2G 的地址, 也不是全给用户的, 低端的 0 - $FFFF 是用于空指针分配, 禁止访问;
高端的 $7FFF0000 - $7FFFFFFF 也留出来作为进程的临界区, 也禁止访问.
其实进程的私有空间地址只有 $10000 - $7FFEFFFF.
*/
// 故意打印没有经过初始化的指针: cout << "&bestE=" << &bestE << ", bestE="<< bestE << endl; // 体会指针的引用:&bestE=0x0012FEAC, bestE=0xCCCCCCCC // 这里证明:1)没有初始化的时候,指针自身的地址是落在用户内存区(0x0012FEAC),指向的地址却是落在系统内存区的(0xCCCCCCCC),所以此时不能使用(*pointer),因为这是禁止访问的区域。 // 2)程序运行时生成的QNode地址全部落在用户内存区 // 3)函数使用带有&的参数QNode<T>*& bestE,使得&bestE永远等于0x0012FEAC,变的仅仅是bestE的值(指针指向的地方)。函数使用不带&的话,函数内部的&bestE将是另外一个值0x0012FE44, while (true) { // 测试左孩子 T wt = Ew + w[i]; if (wt <= c) { // 可行的左孩子 if (wt > bestw) bestw = wt; // 这里已经更新了bestw了,所以记录最佳路径的时候,它们只要相等就代表是最佳路径了 // 左右孩子的E是AddLiveNode里即将生成的QNode的parent,所以左右的节点都有parent AddLiveNode(Q, wt, i, n, bestw, E, bestE, bestx, true); // 左孩子true,代表1 } // 测试右孩子 if (Ew + r > bestw) AddLiveNode(Q, Ew, i, n, bestw, E, bestE, bestx, false); // 右孩子false,代表0 // 左右孩子都检测过了,就要删除当前节点。并且把下一个节点取出放到E里 // E是记录路径的关键 Q.Delete(E); if (!E) { // 除了层结束标志,其它wt都不会等于0 if (Q.IsEmpty()) break; // 找到最优解后跳出循环,准备构建路径 Q.Add(0); // 层结束的标志 Q.Delete(E); i++; r -= w[i]; } // 取出新E-节点的重量,准备下一个循环进行比较 Ew = E->weight; } // 进行了n-1遍循环(这里是4遍循环),除了叶节点直接已经记录下之外,剩下的路径靠它进行回溯取得 for (j=n-1; j>0; j--) { bestx[j] = bestE->LChild; // 判断是取左孩子路径还是右孩子路径 bestE = bestE->parent; // 最佳路径由最新的bestE决定,然后沿着parent向上回溯构建 } return bestw; } void main(void) { int w[6] = {0, 2, 2, 6, 5, 5}; int x[6]; int n = 5; int c = 16; cout << "Max loading is " << GetMaxLoading(w,c,n,x) << endl; cout << "Loading vector is" << endl; for (int i = 1; i <= n; i++) cout << x[i] << ' '; cout << endl; } // ------------------qnode.h文件--------------------------- // used by bbloadc.cpp #ifndef QNode_ #define QNode_ template<class T> class QNode { friend void AddLiveNode(LinkedQueue<QNode<T>*> &, T, int, int, T, QNode<T> *, QNode<T> *&, int *, bool); friend T GetMaxLoading(T *, T, int, int *); private: QNode *parent; // pointer to parent node bool LChild; // true iff left child of parent T weight; // weight of partial solution // defined by path to this node }; #endif // ------------------lqueue.h文件--------------------------- // header file lqueue.h // linked queue #ifndef LinkedQueue_ #define LinkedQueue_ #include "node.h" #include "xcept.h" template<class T> class LinkedQueue { // FIFO objects public: LinkedQueue() {front = rear = 0;} // constructor ~LinkedQueue(); // destructor bool IsEmpty() const {return ((front) ? false : true);} bool IsFull() const; T First() const; // return first element T Last() const; // return last element LinkedQueue<T>& Add(const T& x); LinkedQueue<T>& Delete(T& x); private: Node<T> *front; // pointer to first node Node<T> *rear; // pointer to last node }; template<class T> LinkedQueue<T>::~LinkedQueue() {// Queue destructor. Delete all nodes. Node<T> *next; while (front) { next = front->link; delete front; front = next; } } template<class T> bool LinkedQueue<T>::IsFull() const {// Is the queue full? Node<T> *p; try {p = new Node<T>; delete p; return false;} catch (NoMem) {return true;} } template<class T> T LinkedQueue<T>::First() const {// Return first element of queue. Throw // OutOfBounds exception if the queue is empty. if (IsEmpty()) throw OutOfBounds(); return front->data; } template<class T> T LinkedQueue<T>::Last() const {// Return last element of queue. Throw // OutOfBounds exception if the queue is empty. if (IsEmpty()) throw OutOfBounds(); return rear->data; } template<class T> LinkedQueue<T>& LinkedQueue<T>::Add(const T& x) {// Add x to rear of queue. Do not catch // possible NoMem exception thrown by new. // create node for new element Node<T> *p = new Node<T>; p->data = x; p->link = 0; // add new node to rear of queue if (front) rear->link = p; // queue not empty else front = p; // queue empty rear = p; return *this; } template<class T> LinkedQueue<T>& LinkedQueue<T>::Delete(T& x) {// Delete first element and put it in x. Throw // OutOfBounds exception if the queue is empty. if (IsEmpty()) throw OutOfBounds(); // save element in first node x = front->data; // cout << " x=" << x << endl; // delete first node Node<T> *p = front; front = front->link; delete p; return *this; } #endif
相关文章推荐
- 分支界定法:最大装载问题(使用FIFO)
- 分支界定法:最大装载问题,改进版(使用FIFO)
- 回溯法:最大装载问题(使用递归,优化搜索的同时取得最佳路径)
- git学习--使用git pull命令"当前分支没有跟踪信息"报错问题的解决
- 【C++】使用局部变量赋值而非引用,导致内存多次释放的野指针问题
- ResGen.exe 可能无法运行,因为命令行的长度为XX个字符,超过了命令的最大长度。若要解决此问题,请 (1) 删除不需要的程序集引用,或者 (2) 缩短这些引用的路径。
- python使用中 第三方库引用路径的问题
- 二分图大讲堂——彻底搞定最大匹配数(最小覆盖数)、最大独立数、最小路径覆盖、带权最优匹配(二分图学习)
- 使用STL处理分支限界法处理最优装载问题
- 回溯法:最大装载问题(使用递归,不做任何优化)
- 【python学习】编码时写路径使用后斜杠导致的unicode error问题解决办法
- 使用栈解决迷宫问题(不是最优路径)php
- 使用STL处理分支限界法处理最优装载问题
- vs2008中使用母版页关于引用*.js的[智能语法提示]和[设置路径]的方法和问题
- boost中的智能指针的使用-------解决C++内存问题的最优方案
- 两艘船装在全部货物问题(船舶装载问题)FIFO分支搜索
- vue cli使用绝对路径引用图片问题的解决
- [错误记录]关于指针传递获得数据使用错误问题....
- 初识ExtJS---之使用Extjs框架引用的路径问题
- c++中的指针和引用的使用问题