最短飞行距离
描述
加农肆虐海拉鲁大陆,地面全被毒化了,寸步难行,唯有飞行。
林克透过雷达获得所有塔之间距离以及塔的高度。只有从第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;
}