一、分支定界思想

分支定界思想:一般用来解决寻路问题(最短路径)   广度寻路  A星寻路
    ①常用广度优先或者以最小耗费(最大收益)优先的方式搜索问题的解空间树。
        
    ②在分支定界算法思想中,

 每一个活节点(坐标节点)只有一次机会成为拓展节点
              一旦成为拓展节点,就一次性生成其所有孩子节点。
            在这些孩子节点中,导致不可行解或者非最优解的孩子节点被舍弃(剪枝)
            其余孩子节点被加入活节点表中(存放,记录,保存)
         此后,从活节点表中获取下一节点成为当前拓展节点,并重复上述节点拓展过程。
    这个过程一直到找到需要的解(找到终点)或者活节点表(buff)为空。

③分支定界法常用的两个数据结构:
            1. 队列式分支定界法
                按照队列原则选取下一个节点成为拓展节点。(广度寻路)
            2. 优先队列式分支定界法
                按照优先队列中规定的优先级选取优先级最高的节点成为当前拓展节点(A星寻路)

二、案例一:爬虫

算法流程:

给一个网址 
            解析网址:
            连上网页的服务器
            发送请求到网页服务器,获取网页源码
            源码中就有很多的图片链接和网址链接
            把网址链接存到队列中
            循环从队列中一个个取出 取出后

/*爬虫原理:要求用户输入一个网址获取到这个网址代表的网页的源代码分析源代码:得到    网址得到    网络图片地址网络图片地址  --> 下载图片到本地循环连新的网址去重http协议:客户端连接网页服务器 客户端发送信息给网页服务器,服务器收到后 反馈 传输完数据断开连接基于tcp协议Get  Post  服务器的ip地址和服务器的端口号www.baidu.comhttp://www.netbian.com/s/meinvmm/http://                   //前缀  说明了  协议类型 www.netbian.com         //域名/s/meinvmm/             //路径
*/
#include <regex> //正则表达式头文件
#include <fstream> //文件操作头文件
#include <iostream>
#include <string>
#include <queue>//队列容器
#include <map>//解决网址重复问题
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")//加载动态库   把源代码弄过来
#include <windows.h>using namespace std;
//网址       数据
map<string, int> g_map;//解决网址重复问题
//存放主机名
char g_zhuji[256] = { 0 };
//存放主机后的路径
char g_path[256] = { 0 };
//服务器socket
SOCKET g_socket;
//存放图片地址的容器
vector<string> photoAddr;
//存放网页地址的容器
vector<string> htmlAddr;//爬jpg图片
void snapJpg(const char* addr);
//解析网址
void jiexiAddr(char* buff);
//连接服务器
void connectAddr();
//得到源代码
void getHtml();
//下载图片
void saveImage(string str);
//从网页源代码中获取图片链接
void getImage(string& allHtml);
//从网页源代码中获取网址链接
void getAddr(string& allHtml);
int main(){string begAddr;cout << "请输入起始网址:";cin >> begAddr;//创建一个文件夹CreateDirectory(".\\images", NULL);snapJpg(begAddr.c_str());while (1);return 0;
}
//爬jpg图片
void snapJpg(const char* addr){queue<string> q;//存网址q.push(addr);//把起始网址放进去while (!q.empty()){//从q中拿出一个 string currentAddr = q.front();//删掉q.pop();//解决网址重复问题g_map[currentAddr]++;//解析网址 拿到域名char buff[256] = { 0 };strcpy(buff, currentAddr.c_str());//解析网址jiexiAddr(buff);//连接服务器connectAddr();//得到源代码getHtml();//从源代码中解析出网址和图片地址 存入对应容器中//把网址存放到队列q中vector<string>::iterator it;for (it = htmlAddr.begin(); it != htmlAddr.end(); it++){if (0 == g_map[*it]){//没有连接过q.push(*it);//放到队列中}}htmlAddr.clear();//清空容器//下载图片for (it = photoAddr.begin(); it != photoAddr.end(); it++){saveImage(*it);}photoAddr.clear();//清空容器}
}//解析网址
void jiexiAddr(char* buff){char temp[256] = { 0 };strcpy(temp, buff);//略过前面七个 http://char* p = strstr(buff,"http://");//buff中找子串 "http://" 找到返回子串首地址if (NULL == p) return;elsep += 7;//往后挪七个sscanf(p, "%[^/]%s", g_zhuji, g_path);printf("主机:%s\n", g_zhuji);printf("路径:%s\n", g_path);
}
//连接服务器
void connectAddr(){//1 获取协议版本号WSADATA wsaData;WSAStartup(MAKEWORD(2, 2), &wsaData);if (LOBYTE(wsaData.wVersion) != 2 ||HIBYTE(wsaData.wVersion) != 2){printf("请求版本号失败!\n");return;}printf("请求版本号成功!\n");//2 创建socketg_socket = socket(AF_INET, SOCK_STREAM, 0);if (SOCKET_ERROR == g_socket){printf("创建socket失败!\n");return;}printf("创建socket成功!\n");//3 创建协议地址族SOCKADDR_IN addr = { 0 };addr.sin_family = AF_INET; //必须和socket函数第一个参数一致//4 绑定int r = bind(g_socket, (sockaddr*)&addr, sizeof addr);if (-1 == r){printf("绑定失败!\n");return;}printf("绑定成功!\n");//5 拿到主机ip地址struct hostent* p = gethostbyname(g_zhuji);//192.168.0.44    ipv4if (NULL == p){printf("获取主机地址失败!\n");return;}printf("获取主机地址成功!\n");memcpy(&addr.sin_addr, p->h_addr, 4); //把主机地址放入协议地址族中addr.sin_port = htons(80);              //设置主机端口号   浏览器端口号一般为80//6 连接服务器r = connect(g_socket, (sockaddr*)&addr, sizeof addr);if (-1 == r){printf("连接服务器失败!\n");return;}printf("连接服务器成功!\n");//7 通信:发送获取源代码请求//请求信息string reqInfo = "GET " + (string)g_path + " HTTP/1.1\r\nHost:" +(string)g_zhuji + "\r\nConnection:Close\r\n\r\n";//发送请求信息到服务器r = send(g_socket, reqInfo.c_str(), reqInfo.size(), NULL);if (r > 0){printf("发送请求信息成功!\n");}else{printf("发送请求信息失败,失败原因:%d\n", WSAGetLastError());}}
//得到源代码
void getHtml(){string allHtml;char buff[1024];int r;while (1){r = recv(g_socket, buff, 1023, NULL);if (r > 0){buff[r] = 0;allHtml += buff;}else{break;}}//cout << allHtml << endl;//从网页源代码中获取图片链接getImage(allHtml);//从网页源代码中获取网址链接getAddr(allHtml);
}
//下载图片
void saveImage(string str){//1 解析图片地址char buff[256];memset(buff, 0, 256);strcpy(buff, str.c_str());jiexiAddr(buff);//2 连接服务器//3 发送下载图片请求connectAddr();//4 本地创建图片文件//4.1 得到图片文件名string photoName;photoName.resize(str.size());char ch;int j = 0;for (int i = 0; i < str.length(); i++){ch = str[i];// '\0'  '\n' '\t' '\r' '\\' '\"'if (ch != '\\' && ch != '/' && ch != ':' && ch != '*' && ch != '?' &&ch != '"' && ch != '<' && ch != '>' && ch != '|'){photoName[j++] = ch;}}photoName = "./images/" + photoName.substr(0, j);//4.2 创建图片文件fstream file;file.open(photoName, ios::out | ios::binary);//二进制写//5 接收发送过来的图片信息并写入图片文件中int r;char tempBuff[1024] = { 0 };//排除掉文件头的"\r\n\r\n"r = recv(g_socket, tempBuff, 1023, NULL);char* p = strstr(tempBuff, "\r\n\r\n");file.write(p + strlen("\r\n\r\n"), r - (p - tempBuff) - strlen("\r\n\r\n"));while (1){r = recv(g_socket, tempBuff, 1023, NULL);if (r > 0){file.write(tempBuff, r);}else{break;}}//6 保存关闭file.close();}//从网页源代码中获取图片链接
void getImage(string& allHtml){smatch mat;//用作匹配的对象regex pattren("src=\"(.*?\\.jpg)\"");string::const_iterator start = allHtml.begin();//起始位置string::const_iterator end = allHtml.end();//结束位置while (regex_search(start, end, mat, pattren)){string msg(mat[1].first, mat[1].second);photoAddr.push_back(msg);cout << "找到图片:" << msg << endl;start = mat[0].second;//改变起始位置}
}
//从网页源代码中获取网址链接
void getAddr(string& allHtml){smatch mat;//用作匹配的对象regex pattren("href=\"(http://[^\\s,\"]+)\"");string::const_iterator start = allHtml.begin();//起始位置string::const_iterator end = allHtml.end();//结束位置while (regex_search(start, end, mat, pattren)){string msg(mat[1].first, mat[1].second);htmlAddr.push_back(msg);cout << "找到网址:" << msg << endl;start = mat[0].second;//改变起始位置}
}

三、案例二:图的A*寻路算法

#include <iostream>
#include <vector>
#include <limits>//numeric_limits
#include <queue>
using namespace std;//节点类
class Node {
public://属性  一般应该是 private 或者 protectedint      index;      //序号int     weight;     //权重
public://功能//构造Node(int index = 0, int weight = 0) :index(index), weight(weight) {}//拷贝构造Node(const Node& object) :index(object.index), weight(object.weight) {}//重载小于运算符   为了比较  剪枝friend bool operator<(const Node& one, const Node& two) {return (one.weight > two.weight);}
};//路径类   节点类是边  路径类其实是很多节点相加
class Path {
public://属性  一般应该是 private 或者 protectedint      index;      //序号int     weight;     //权重
public://功能Path() :index(0), weight(numeric_limits<int>::max()) {}
};class shortTestPath {
public://属性vector<vector<int>>      graph;      //图int                      nodeCount;  //节点统计const int             edge;       //起始const int               end;        //结束vector<int>               pathIndex;  //存储最短路径的容器int                      shortPath;  //最短路径值
public://功能//构造函数shortTestPath(const vector<vector<int>>& object, int end) :edge(-1), end(end),nodeCount(object.size()), graph(object) {}//打印void printPath() {cout << "最短路径值:" << shortPath << endl;cout << "路径:";//反向打印copy(pathIndex.rbegin(), pathIndex.rend(),ostream_iterator<int>(cout, " "));cout << endl;}void getShortTestPath() {vector<Path> myPath(nodeCount);//初始化路径容器大小priority_queue<Node, vector<Node>> minHeap;//准备一个优先队列(小顶堆)minHeap.push(Node(0, 0));//入口入堆while (1) {Node top = minHeap.top();minHeap.pop();//如果是终点,结束循环if (top.index == end) break;for (int i = 0; i < nodeCount; i++) {//剪枝过程if (graph[top.index][i] != edge &&top.weight + graph[top.index][i] < myPath[i].weight) {minHeap.push(Node(i, top.weight + graph[top.index][i]));myPath[i].index = top.index;myPath[i].weight = top.weight + graph[top.index][i];}}//最终堆空了,还没找到终点if (minHeap.empty()) break;}//end of while (1)//求路径和shortPath = myPath[end].weight;//求路径int index = end;pathIndex.push_back(index);while (1) {index = myPath[index].index;pathIndex.push_back(index);if (0 == index) break;}}
};int main() {//准备图结构const int size = 11;//顶点个数vector<vector<int>> graph(size);for (int i = 0; i < size; i++) {graph[i].resize(size);//重置大小  开空间}//赋值for (int i = 0; i < size; i++) {for (int j = 0; j < size; j++) {graph[i][j] = -1;}}graph[0][1] = 2;graph[0][2] = 3;graph[0][3] = 4;graph[1][2] = 3;graph[1][4] = 7;graph[1][5] = 2;graph[2][6] = 2;graph[2][5] = 9;graph[3][6] = 2;graph[4][7] = 3;graph[4][8] = 3;graph[5][6] = 1;graph[5][8] = 3;graph[6][9] = 1;graph[6][8] = 5;graph[7][10] = 3;graph[8][10] = 2;graph[9][8] = 2;graph[9][10] = 2;//创建shortTestPath对象shortTestPath sPath(graph, 10);sPath.getShortTestPath();sPath.printPath();while (1);return 0;
}

Day23:算法之分支定界相关推荐

  1. 贪心算法和分枝定界算法的区别

    1.贪心算法 贪心算法(贪婪算法)就是在对问题进行求解时,总是做出当前看起来最优的选择,就是不从整体上进行考虑,只是得到局部意义上的最优解.贪心不是对问题都能得到全局最优解,关键在于贪心策略的选择. ...

  2. tsp 分支界限 java_干货 | 10分钟教你用branch and bound(分支定界)算法求解TSP旅行商问题...

    在此之前,先给大家讲讲最重要的一个点,搜索树的节点定义,节点定义了原问题的solution和子问题的solution.Node节点定义如下: public class Node {private Ar ...

  3. branch and bound(分支定界)算法-基础概念

    网址1:干货 | 10分钟带你全面掌握branch and bound(分支定界)算法-概念篇 网址2:运筹优化学习10:分支定界算法求解整数规划问题及其Matlab实现

  4. 分支定界法 python_分支定界(Branchbound)算法

    背包问题,一般可以用动态规划解决.当涉及到的物体数目比较多,填表法所需要的存储空间很大$O(nW)$,每次都以内存不足告终. 参考: https://www.geeksforgeeks.org/imp ...

  5. 数学建模基础算法Chapter2.1 -- 整数规划(ILP): 分支定界+割平面

    Chapter2.1 – 整数规划(ILP) By 进栈需检票 一.前情提要 当题目要求的最优解是整数,例如物件的数量,参与人员的数量等时,就不能继续使用之前的线性规划了(当出现小数的情况),这个时候 ...

  6. 分支定界算法在中学排课问题中的应用

    分支定界算法在中学排课问题中的应用 摘要:在本文中我们主要研究了带约束有教案的中学排课程表问题.首先我们得到了有关该问题的中学课程表必须满足的几个条件,因为该排课程表问题是一个NP难解的问题,因此该问 ...

  7. 分支定界算法理解(摘抄)

    解释一 分支定界算法(Branch and bound,简称为 BB.B&B, or BnB)始终围绕着一颗搜索树进行的. 我们将原问题看作搜索树的根节点.从这里出发,分支的含义就是将大的问题 ...

  8. 5.1 基于分支定界算法的单机调度

    原创文章,禁止转载.抄袭或用于报告.交流等学术或商业用途 全文(其它章节内容) https://blog.csdn.net/qq_38757869/article/details/106885769 ...

  9. branch and bound(分支定界)算法求解TSP旅行商问题

    转载自:分枝定界算法求解TSP 整个程序如下所示: 其中各个模块说明如下: - Timer:计时用. - TSPInstanceReader:TSPLIB标准算例读取用. - PriorityQueu ...

  10. branch and bound(分支定界)算法

    最近在看cartographer算法,其中的闭环优化使用到了branch and bound(分支定界)算法,这里简单记录一下: 分支定界算法是一种求解离散最优化问题的计算分析方法.它是由R.J.达金 ...

最新文章

  1. 三维空间碰撞问题;空间中两直线的最短距离及最近点
  2. 正则表达式之python3版
  3. 极简版 卸载 home 扩充 根分区--centos7 xfs 文件格式
  4. WPF 从 .net core 3.1 到 .net 5.0
  5. ionic2 安装与cordova打包
  6. 南邮哈夫曼编码c语言代码_漫画:“哈夫曼编码” 是什么鬼?
  7. postman如何模拟Map参数请求呢?
  8. mysql 事件状态enable_mysql事件 - wayhk的个人页面 - OSCHINA - 中文开源技术交流社区...
  9. 甘肃电大计算机考试题2007,甘肃电大2021年春季《C++语言程序设计(专)》形成性考核二满分...
  10. CSS calc()函数的用法
  11. 【教程篇】手机卡刷Rom详细教程
  12. Lua unpack函数用法
  13. 如何让 MacBook 最适化 macOS Big Sur 和 Monterey 电池
  14. 合肥工业大学计算机与信息学院复试,合肥工业大学计算机与信息学院2018考研大纲(复试)...
  15. 绝密隐私!有趣的网络摄像头大揭露
  16. linux给变量加单引号,grep中加单引号与不加引号的区别
  17. 微信小程序 - 修改 button 边框和背景色
  18. 实现动画切换渐进渐出效果
  19. Tensorflow学习之tf.keras(一) tf.keras.layers.Model(另附compile,fit)
  20. 为什么大家认为中台不能用于传统行业?

热门文章

  1. web下拉菜单代码html,简单的单级下拉菜单实现_html/css_WEB-ITnose
  2. 全志android编译过程
  3. LINUX重新编译BIN固件,固件编译
  4. 虚拟主机和云服务器有什么区别,我们应该如何选择?
  5. 关注Oracle 02 财务系统的选型想说简单不容易
  6. snb处理器hd3000显卡专用extra_Intel十代酷睿处理器:移动平台性能有了质飞跃!...
  7. 为什么mydock会经常崩溃_MyDock
  8. ScreenToClient 和 ClientToScreen
  9. STM32F407软件模拟IIC驱动RX8025程序加原理图
  10. Msm8960(APQ8064)平台的MSM-AOSP-kitkat编译适配(4):验证代码并编写自己的device