技术学习总结
学习技术一定要制定一个明确的学习路线,这样才能高效的学习,不必要做无效功,既浪费时间又得不到什么效率,大家不妨按照我这份路线来学习。
最后面试分享
大家不妨直接在牛客和力扣上多刷题,同时,我也拿了一些面试题跟大家分享,也是从一些大佬那里获得的,大家不妨多刷刷题,为金九银十冲一波!
而分支限界想求出的解只有一个最优解,对解的空间树的搜索方式为 BFS
===================================================================
思路:
1.注意题目给出的完全有向图:
有向完全图是指概述图中各边都有方向,且每两个顶点之间都有两条方向相反的边连接的图。
2.通过分析据我们不难发现,每两个顶点间的距离是不一样的
3.写码思路:
<1>:本题解空间是排列树
<2>:我们在遍历树的时候我们采用的BFS,采用的数据结构是优先队列。
<3>:每次在选择扩展结点的时候,我们自定义的排序规则是将已有路径最小的先选择
<4>:选完扩展结点的时候,我们就要处理该扩展结点的邻接点,到达邻接点的距离小于bestw,我们就将该邻接点
统计到队列中
同时更新到达该结点路径程度,记录已经选择的路径顺序(x[i]),因为我们每次选择
的结点不同,所以我们记录的路径顺序也会有变化,那么就需要swap(x[t],x[j]),
这时候,我们就能得到正确的路径顺序。
<5>:当我们要遍历到叶节点的时候,这时候就要更新我们的bestw,将到达最后一个结点的距离加上
最后一个结点到源结点的距离 和 bestw进行比较更新,比其小就更新bestw,
否则,就跳过本轮循环,因为我们我们已经知道了其再往下走,也是不可能比bestw更小了
===================================================================
/**
思路:
1.注意题目给出的完全有向图:
有向完全图是指概述图中各边都有方向,且每两个顶点之间都有两条方向相反的边连接的图。
2.通过分析据我们不难发现,每两个顶点间的距离是不一样的
3.写码思路:
<1>:本题解空间是排列树
<2>:我们在遍历树的时候我们采用的BFS,采用的数据结构是优先队列。
<3>:每次在选择扩展结点的时候,我们自定义的排序规则是将已有路径最小的先选择
<4>:选完扩展结点的时候,我们就要处理该扩展结点的邻接点,到达邻接点的距离小于bestw,我们就将该邻接点
统计到队列中
同时更新到达该结点路径程度,记录已经选择的路径顺序(x[i]),因为我们每次选择
的结点不同,所以我们记录的路径顺序也会有变化,那么就需要swap(x[t],x[j]),
这时候,我们就能得到正确的路径顺序。
<5>:当我们要遍历到叶节点的时候,这时候就要更新我们的bestw,将到达最后一个结点的距离加上
最后一个结点到源结点的距离 和 bestw进行比较更新,比其小就更新bestw,
否则,就跳过本轮循环,因为我们我们已经知道了其再往下走,也是不可能比bestw更小了
*/
#include<bits/stdc++.h>
using namespace std;
int INF=999999999;
const int N=100; //const 初始化
int maps[N][N]; //存储图
int n,m; //n表示顶点数,m表示边数
int bestw;
struct Node
{
int x[N]; //解向量,方便从1开始,记录路径
int cl; //表示当前已走过的路径长度
int id; //表示层数
};
//重写 优先队列当中排序方法 按每次路径最短的升序处理
bool operator<(const Node &a,const Node &b){
return a.cl>b.cl;
}
void bfs()
{
priority_queueq;
Node node;
node.cl = 0; // 0 表示当前已经的走的路径长度,2表示层数
node.id = 2;
//表示的是每个结点的序号,用于记录树当中路径
for(int i=1;i<=n;i++){
node.x[i]=i;
}
q.push(node);
while(!q.empty()){
//这个新结点的信息就是上方的node,其解向量为 1,2,3,4…而c = 0 id = 2;
Node newnode=q.top();
q.pop();
int t;
t = newnode.id;//当前层数
if(tn){//当n4的时候,其实是走了3个结点两个距离,所以还需要判断与最后一个结点
//的距离,以及最后一个结点和首节点的距离。
//如果两个结点中有一个的距离是无穷的那么,它的路径长度肯定不满足要求
if(maps[newnode.x[t-1]][newnode.x[n]] != INF
&& maps[newnode.x[n]][newnode.x[1]] != INF ){
//如果满足要求的话,那么就要判断已有的路径长度+到最后一个结点长度
//+最后一个结点到源结点的距离。
if(newnode.cl + maps[newnode.x[t-1]][newnode.x[n]]
- maps[newnode.x[n]][newnode.x[1]] < bestw){
bestw = newnode.cl+maps[newnode.x[t-1]][newnode.x[n]]
- maps[newnode.x[n]][newnode.x[1]];//更新bestw;
} else{//如果我们已经知道其最后的总路程是大于bestw的话,那就没有必要再统计其邻接点了
continue;
}
}else{//这里也是,如果我们已经知道其到达最后一个结点,或是最后一个结点到达首结点
//的距离是无穷的,那么我们就没必要再往下统计了
continue;
}
}
if(newnode.cl >= bestw) continue;//限界条件
//拿出队列当中的头节点,扩展其所有的分支
for(int j = t; j <= n; j++){//扩展所有分支
//这里是将当前的结点的临界点遍历,但是需要比较已有的路径
//长度跟当前的最优值,比其小才遍历,否则的话,再往下进行肯定是比最优值大的
//因为结点层数是比矩阵当中记录的行数多1,所以要减去。
if(newnode.cl + maps[newnode.x[t-1]][newnode.x[j]] < bestw){
int c = newnode.cl + maps[newnode.x[t-1]][newnode.x[j]];
//生成一个新的结点 且更新现在的路径长度和遍历的树的层数
Node node;
node.cl = c;
node.id = t+1;
//复制父节点的解向量
for(int i = 1; i <= n; i++)
node.x[i] = newnode.x[i];
//这个交换是为了 扩展结点可以在下一次的加入邻接点(活结点)的时候
//可以正确统计该活结点在矩阵当中的正确行数
swap(node.x[t],node.x[j]);
q.push(node);
}
}
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j = 1; j <= n; j++) {
int w;
cin >> w;
if(w == 0)
maps[i][j] = INF;
else
maps[i][j] = w;
}
}
bestw=INF;
bfs();
cout << bestw;
最后
由于篇幅限制,小编在此截出几张知识讲解的图解
5799344204)]
[外链图片转存中…(img-coTE8SO8-1715799344204)]
[外链图片转存中…(img-F5rPfJg7-1715799344205)]
[外链图片转存中…(img-zixDH4Xk-1715799344205)]
[外链图片转存中…(img-eentMruz-1715799344206)]