题目
726:ROADS
总时间限制: 1000ms 内存限制: 65536kB
描述
N cities named with numbers 1 … N are connected with one-way roads. Each road has two parameters associated with it : the road length and the toll that needs to be paid for the road (expressed in the number of coins).
Bob and Alice used to live in the city 1. After noticing that Alice was cheating in the card game they liked to play, Bob broke up with her and decided to move away - to the city N. He wants to get there as quickly as possible, but he is short on cash.
We want to help Bob to find the shortest path from the city 1 to the city N that he can afford with the amount of money he has.
输入
The first line of the input contains the integer K, 0 <= K <= 10000, maximum number of coins that Bob can spend on his way.
The second line contains the integer N, 2 <= N <= 100, the total number of cities.
The third line contains the integer R, 1 <= R <= 10000, the total number of roads.
Each of the following R lines describes one road by specifying integers S, D, L and T separated by single blank characters :
S is the source city, 1 <= S <= N
D is the destination city, 1 <= D <= N
L is the road length, 1 <= L <= 100
T is the toll (expressed in the number of coins), 0 <= T <=100
Notice that different roads may have the same source and destination cities.
输出
The first and the only line of the output should contain the total length of the shortest path from the city 1 to the city N whose total toll is less than or equal K coins.
If such path does not exist, only number -1 should be written to the output.
样例输入
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
样例输出
11
翻译
题目:道路
描述:
以数字1命名的N个城市。。。N与单行道相连。每条道路都有两个相关参数:
道路长度和需要支付的道路通行费(以硬币数量表示)。
鲍勃和爱丽丝以前住在城里。在注意到爱丽丝在他们喜欢玩的纸牌游戏中作弊后,
鲍勃和她分手了,决定搬到N市。他想尽快赶到那里,但他缺钱。
我们想帮助Bob找到从城市1到城市N的最短路径,只要他有足够的钱。
输入:
输入的第一行包含整数K,0<=K<=10000,Bob在路上可以花费的最大硬币数。
第二行包含整数N,2<=N<=100,城市总数。
第三行包含整数R,1<=R<=10000,道路总数。
以下R行中的每一行都通过指定由单个空白字符分隔的整数S、D、L和T来描述一条道路:
S是源城市,1<=S<=N
D是目的地城市,1<=D<=N
L是道路长度,1<=L<=100
T是通行费(以硬币数量表示),0<=T<=100
请注意,不同的道路可能有相同的起点和终点城市。
输出:
输出的第一行也是唯一一行应包含从城市1到城市N的最短路径的总长度,N的总通行费小于或等于K硬币。
如果不存在这样的路径,则只应将数字-1写入输出。
代码
#include <bits/stdc++.h>
using namespace std;
const int maxd=numeric_limits<int>::max();//整型数据类型的最大值
struct roads{//道路
int d,//目标城市
l,//路长
t;//费用
roads(int dx,int lx,int tx):d(dx),l(lx),t(tx){};//构造函数加直接赋值,顺序初始化
};
vector<roads> road[110];//两点间可能有多条路,二维数组
struct citys{
int s,//哪个城市
l,//路长
t;//费用
bool operator<(const citys& b)const{//引用且不能改,避免拷贝。
if(l!=b.l)return l>b.l;
else return t>b.t;
}
}c;
int dis[110][10010];//[城市][费用]=每城市每合格费用对应的最短距离
priority_queue<citys> q;//优先队列(降序,最小堆)
int k,//硬币数
n,//城市数
r,//道路数
ans=maxd;//应允费用下的最少路长
int main(){
//freopen("data.cpp","r",stdin);
cin>>k>>n>>r;
int s,//源城市
d,//目的城市
l,//长度
t;//费用
for(int i=1;i<=r;i++){
cin>>s>>d>>l>>t;
road[s].push_back(roads{d,l,t});//s开始的所有道路
}
q.push(citys{1,0,0});//队列里只有城市1,从一城市出发dijs
for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++)dis[i][j]=maxd;//找合适费用下的最少路长
dis[1][0]=0;//从城市1出发,0费用时的路长是0
while(!q.empty()){//宽搜
c=q.top();q.pop();//出发城市
if(c.s==n&&c.t<=k)ans=min(ans,c.l);//在合适费用时到目标城市的最少路长
for(vector<roads>::iterator c2=road[c.s].begin();c2!=road[c.s].end();c2++){
//遍历该城市能到达的城市
int cost=c.t+c2->t,//出发城市的费用+道路费用
len=c.l+c2->l;//出发城市的已有路长+道路路长
if(cost>k)continue;//超出限额不能用
if(len>=dis[c2->d][cost])continue;//超出现有金额下的最短路长也不用
dis[c2->d][cost]=len;//该金额下的更短路长
//cout<<c.s<<"到城市"<<i<<"\n出发前费用:"<<c.t<<"\t现在费用:"<<cost<<"\t";
//cout<<"该费用时的最短路程:"<<dis[i][cost]<<endl;;
q.push(citys{c2->d,len,cost});//新的出发城市
}
}
cout<<(ans==maxd?-1:ans);
return 0;
}
图
执行流程:
初始化队列 {1,0,0}
扩展城市1:
到2:费用3 ≤穷,更新 dis[2][3]=2
到3:费用1 ≤穷,更新 dis[3][1]=4
弹出城市2:
到4:费用3+3 >5,(跳过)
弹出城市3:
到4:费用1+4<=5,更新 dis[4][5]=6
到5:费用1+0 ≤5,更新 dis[5][1]=6
弹出城市4:
到6:费用5+1>5,(跳过)
到5:费用5+2 >5,(跳过)
弹出城市5:
到4:费用1+2<=5,更新 dis[4][3]=9
弹出城市4:
到6:费用3+1<=5,更新 dis[6][4]=11
最终找到 dis[4][2]=5 为最优解
算法分析
采用 优先队列优化的动态规划(Dijkstra变种),通过 二维状态转移 维护以下关键信息:
状态定义
dis[i][j]:到达城市 i 时 总费用为 j 的最小路径长度
优先队列
存储结构体 citys,按 路径长度优先(小顶堆),其次费用更低优先。
每次弹出当前最短路径状态进行扩展。
状态转移
对于当前状态 (s, l, t) 和道路 (d, l_road, t_road):
新费用 new_t = t + t_road
新路径长度 new_l = l + l_road
若满足:
new_t ≤ k(费用不超限)
new_l < dis[d][new_t](发现更短路径)
则更新状态并加入队列。
通过二维状态设计与优先队列结合,解决了带费用约束的最短路径问题