算法实践:最短飞行距离

最短飞行距离

描述

加农肆虐海拉鲁大陆,地面全被毒化了,寸步难行,唯有飞行。

林克透过雷达获得所有塔之间距离以及塔的高度。只有从第N座塔——平原之塔上才可以给予加农致命一击。

已知N座塔(1…N),塔与塔之间只有唯一的一条飞行路线,从塔A到塔B,需要消耗不同的精力药水(飞行以及爬塔都需要)。

假设原始塔s与目标塔d之间的距离是length,需要消耗的精力药水是cost。则每一条路线就可以表示为如下的一组数据:
(s,d,length,cost)

林克身上只有B瓶精力药水,请帮他找到能够飞到第N座塔的最短路径长度。

在这里插入图片描述

输入

第一行是一个整数B ,表示林克携带的精力药水数(0 <= B <= 10000)。

第二行是整数N,表示一共有N座塔(2 <= N <= 100)。

第三行是整数R,表示一共有R条飞行路线(1 <= R <= 10000)

接下来有R行数据,每行数据是一个由空格隔开的四元组 (s,d,length,cost)

  • s 初始塔, 1 <= s <= N
  • d目标塔, 1 <= d <= N
  • length路线长度, 1 <= length <= 100
  • cost 此条路线必须消耗的精力药水数, 0 <= cost <=100

注意,从一个塔到另一个塔可能有不同的飞行路线。

输出

输出从塔1飞到塔N的所有路线中,最短路径的长度。(注意,林克抵达塔N的时候精力药水应该>=0)

如果林克无论如何都抵达不了塔N,请输出-1。

样例

5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
7

难度

高,dfs

解法

利用深度优先搜索寻找从1 —> N 的所有路径,并寻找最小的那一条输出,数据结构采用邻接表,这里用了一个嵌套容器vector实现。

两个剪枝条件:

从第i座塔出发前,其累计的飞行距离step已经比当前的minLen还要大,从此点之后的分支无需计算

从第i座塔出发前,其累计消耗的精力药水cost已经比B大,药水用完了,此分支无需计算

代码

//write by Andy
#include <bits/stdc++.h>
using namespace std;
int B,N,R;  //精力药水、N座塔,R条路
struct AirLine{
    int d,length,cost;
};
vector< vector<AirLine> > maps(110); //邻接表
void add_edge(int s,int d,int length,int cost)
{
    AirLine dTower;
    dTower.d = d;
    dTower.length = length;
    dTower.cost = cost;
    if(s!=d){
        maps[s].push_back(dTower);
    }
}
int minLen;
int totalLen;
int totalCost;
int visited[110];  //是否已经访问过
void dfs(int i,int step,int cost){   //第i座塔,step表示已经length的长度,cost当前消耗的药水
    if(cost>B || step>minLen)  //剪枝
        return;
    if(i==N){
        minLen = min(minLen,step);
        return;
    }
    for(int k=0;k<maps[i].size();k++){
        AirLine pTower = maps[i][k];
        if(!visited[pTower.d]){
            visited[pTower.d] = 1;
            dfs(pTower.d,step+pTower.length,cost+pTower.cost);
            visited[pTower.d] = 0;   //深度优先搜索注意还原pTower
        }
    }
}
int main() {
    cin>>B>>N>>R;
    for(int i=1;i<=R;i++){
        int s,d,l,c; cin>>s>>d>>l>>c;
        add_edge(s,d,l,c);
    }
    //初始化全局变量
    memset(visited,0,110);
    totalCost=0,totalLen=0,minLen= 1<<30 ;
    visited[1]=1;
    dfs(1,0,0);
    cout<<((minLen < (1<<30) )?minLen:-1)<<endl;
    return 0;
}

发布了129 篇原创文章 · 获赞 148 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/matafeiyanll/article/details/105300569