一、题目
二、解题
1.利用BFS求解
以下这段代码实现了一个广度优先搜索算法(bfs)来查找一个有权有向图中,从点0到点1的最短路径长度。这里的点编号从0开始,而点0是起点,点1是终点。对于一个由n个普通点和m个特殊点组成的有向图,其中k表示每个点最多可以经过的次数,r表示两个点之间的距离不能超过r,c[i]表示当前到点i的路径经过的普通点数,cnt_n表示当前路径经过的普通点数,cnt_t表示经过特殊点的次数。
算法流程如下:
- 首先定义一个队列,将起点(0, 0, 0)加入队列。
- 使用fill函数将c数组初始化,设置为k+1,表示尚未到任何一个点。
- 取出队首元素temp,分别取出其节点编号(index)、当前经过的普通点数(c1)、经过特殊点的次数(c2)。
- 如果当前节点为终点1,则返回经过特殊点的次数(c2-1)。
- 对于当前节点temp,遍历它所能到达的所有节点i。
- 如果遍历到的是特殊点n,则普通点数c1加一。
- 如果当前普通点数c1已经达到了k,说明到达该点的路径已经经过了k个普通点,需要停止从该点扩展路径搜索。
- 如果从当前节点temp到节点i的距离d[index][i]不超过r,且到达节点i的路径经过的普通点数c[i]大于当前普通点数c1,更新c[i]并将节点(i,c1,c2+1)加入队列,表示从当前节点到达节点i需要经过一个特殊点。
- 如果队列不为空,重复步骤3-8,直到找到终点或者队列为空为止。
int bfs(){
queue<node> q;
q.push((node){0,0,0});
fill(c+1,c+n+m,k+1);
while(!q.empty()){
node temp=q.front();
q.pop();
int index=temp.id,c1=temp.cnt_n,c2=temp.cnt_t;
if(index==1) return c2-1;
for(int i=0;i<n+m;i++){
if(i==n) c1++;
if(c1>k) break;
if(d[index][i]<=r && c1<c[i]){
c[i]=c1;
q.push((node){i,c1,c2+1});
}
}
}
}
2.代码
dev c++ 5.11
#include<bits/stdc++.h>
using namespace std;
const int N=200;
int n,m,k,r;
//x[i],y[i]存储所有路由器坐标,大于n时为新增路由器,c[i]表示从起点到i所经过的新增路由器的数量
int x[N],y[N],c[N]={0};
//d[i][j]存储距离信息
double d[N][N]={0};
//用于bfs, cnt_n表示经过的新增路由器数量, cnt_t表示经过的总的路由器数量
struct node{
int id,cnt_n,cnt_t;
};
double dist(int i,int j){
double res=pow(1.0*x[i]-x[j], 2.0) + pow(1.0*y[i]-y[j], 2.0);
return sqrt(res);
}
int bfs(){
queue<node> q;
q.push((node){0,0,0});
fill(c+1,c+n+m,k+1);
while(!q.empty()){
node temp=q.front();
q.pop();
int index=temp.id,c1=temp.cnt_n,c2=temp.cnt_t;
if(index==1) return c2-1;
for(int i=0;i<n+m;i++){
if(i==n) c1++;
if(c1>k) break;
if(d[index][i]<=r && c1<c[i]){
c[i]=c1;
q.push((node){i,c1,c2+1});
}
}
}
}
int main(){
cin>>n>>m>>k>>r;
for(int i=0;i<n+m;i++){
cin>>x[i]>>y[i];
}
for(int i=0;i<n+m;i++){
for(int j=i+1;j<n+m;j++){
d[j][i]=d[i][j]=dist(i,j);
}
}
cout<<bfs()<<endl;
return 0;
}
该处使用的url网络请求的数据。
3.提交结果
总结
综上,该算法使用了bfs来遍历有权图中的所有节点,找到从起点到终点的最短路径。通过限制从每个点出发经过的普通点数和距离,可以避免掉入死循环,同时保证算法的效率和正确性。
1.解释
- 利用对称矩阵存储距离信息,即把距离存储到 d[i][j] 和 d[j][i] 两个位置上。
for(int i=0;i<n+m;i++){
for(int j=i+1;j<n+m;j++){
d[j][i]=d[i][j]=dist(i,j);
}
}
- 初始化函数fill()。
下面这段代码使用C++中的fill()函数,对从c+1索引开始的连续m+n个元素都赋值为k+1。其中:
- c是指向数组首元素的指针;
- m和n是两个整数;
- k也是一个整数。
fill(c+1,c+n+m,k+1);
这段代码的作用是初始化一段长度为m+n,以指针c所指向的位置为起点的连续内存空间,将它们的值都设定为k+1。