百练1724 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 的走法, 选一个最优的。
优化:
1) 如果当前已经找到的最优路径长度为L ,那么在继续搜索的过程中,总长度已经大于L的走法,就可以直接放弃,不用走到底了 。
2) 用midL[k][m] 表示:走到城市k时总过路费为m的条件下,最优路径的长度。若在后续的搜索中,再次走到k时,如果总路费恰好为m,且此时的路径长度已经超过midL[k][m],则不必再走下去了。
AC代码
#include<iostream> #include<vector> #include<algorithm> #include<cstring> using namespace std; int K, N, R, S, D, L, T;//Bob的金额,目标城市编号,道路总数,路的起点和终点,长度和过路费 struct Road { int d, L, t;//终点,长度和过路费 }; vector<vector<Road> >cityMap(110);//邻接表,cityMap[i]是以城市i为起点的道路集合 int minLen = 1 << 30;//当前找到的最优路径的长度 int totalLen;//当前走过的总路径长度 int totalCost;//当前总花销 int visited[110];//城市是否已经走过的标记 int minL[110][10100];//minL[i][j]表示从1到i点的,花销为j的最短路的长度 void Dfs(int s)//从s开始向N行走 { if (s == N)//已经达到目标点 { minLen = min(minLen, totalLen); return; } for (int i = 0; i < cityMap[s].size(); i++)//遍历s连接的道路 { int d = cityMap[s][i].d;//s的第i条道路的目的地 if (!visited[d])//还没有访问过d { int cost = totalCost + cityMap[s][i].t; if (cost > K)continue;//如果花销已经大于Bob手里的钱那就没戏了 //如果当前总路径大于已知的可行最小路径,或者相同总开销情况下,当前总路径大于d城市已知的最小路径,一样没戏 if (totalLen + cityMap[s][i].L >= minLen || totalLen + cityMap[s][i].L >= minL[d][cost])continue; totalLen += cityMap[s][i].L; totalCost += cityMap[s][i].t; minL[d][cost] = totalLen; visited[d] = 1;//重重考验之后d被接纳为最优路径上一点 Dfs(d);//递归解法,继续遍历d visited[d] = 0; totalCost -= cityMap[s][i].t; totalLen -= cityMap[s][i].L;//在遍历d之后没有找到目标结点,返回途中把d结点删除 } } } int main() { cin >> K >> N >> R; for (int i = 0; i < R; i++) { int s; Road r; cin >> s >> r.d >> r.L >> r.t; if (s != r.d) cityMap[s].push_back(r); } for (int i = 0; i < 110; i++) for (int j = 0; j < 10100; j++) minL[i][j] = 1 << 30; memset(visited, 0, sizeof(visited)); totalLen = 0; totalCost = 0; visited[1] = 1;//1城市为起点,已访问 minLen = 1 << 30; Dfs(1);//启动深搜 if (minLen < (1 << 30)) cout << minLen << endl; else cout << -1 << endl; return 0; }