poj1724 ROADS

题意:

N个城市,编号1到N。城市间有R条单向道路。
每条道路连接两个城市,有长度和过路费两个属性。
Bob只有K块钱,他想从城市1走到城市N。问最短共需要走多长的路。如果到不了N,输出-1
2<=N<=100
0<=K<=10000
1<=R<=10000
每条路的长度 L, 1 <= L <= 100
每条路的过路费T , 0 <= T <= 100

思路:

用d[i][j]表示从源点走到城市i并且花费为j的时候经过的最短距离。若在后续的搜索中,再次走到i时,如果总路费恰好为j,且此时的路径长度已经超过 d[i][j],则不必再走下去了。

1.深搜+剪枝

2.spfa+剪枝

实现:

1.

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <vector>
 5 #include <cstring>
 6 using namespace std;
 7 
 8 const int MAXN = 100;
 9 const int MAXK = 10000;
10 const int INF = 0x3f3f3f3f;
11 
12 struct node
13 {
14     int to, len, toll;
15 };
16 vector<node> G[MAXN + 5];
17 int k, n, m, s, t, l, T, minLen = INF;
18 
19 bool vis[MAXN + 10];
20 int d[MAXN + 5][MAXK + 5];
21 
22 void dfs(int now, int rem, int len)
23 {
24     if (now == n)
25     {
26         minLen = min(minLen, len);
27         return;
28     }
29     for (int i = G[now].size() - 1; i >= 0; i--)
30     {
31         if (!vis[G[now][i].to] && rem >= G[now][i].toll)
32         {
33             if (d[G[now][i].to][rem - G[now][i].toll] <= 
34                 len + G[now][i].len || len + G[now][i].len >= minLen)
35                 continue;
36             d[G[now][i].to][rem - G[now][i].toll] = len + G[now][i].len;
37             dfs(G[now][i].to, rem - G[now][i].toll, len + G[now][i].len);
38             vis[G[now][i].to] = false;
39         }
40     }
41 }
42 
43 int main()
44 {
45     cin >> k >> n >> m;
46     for (int i = 0; i < m; i++)
47     {
48         cin >> s >> t >> l >> T;
49         node tmp;
50         tmp.to = t;
51         tmp.len = l;
52         tmp.toll = T;
53         if (s != t)
54             G[s].push_back(tmp);
55     }
56     memset(d, 0x3f, sizeof(d));
57     vis[1] = true;
58     dfs(1, k, 0);
59     if (minLen == INF)
60         puts("-1");
61     else
62         cout << minLen << endl;
63     return 0;
64 }

2.

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <vector>
  5 #include <cstring>
  6 #include <queue>
  7 #include <functional>
  8 using namespace std;
  9 
 10 const int MAXN = 100;
 11 const int MAXK = 10000;
 12 const int INF = 0x3f3f3f3f;
 13 
 14 struct node
 15 {
 16     int to, len, toll;
 17 };
 18 vector<node> G[MAXN + 5];
 19 int k, n, m, s, t, l, T;
 20 
 21 struct co
 22 {
 23     int now, cost;
 24 };
 25 
 26 int d[MAXN + 5][MAXK + 5];
 27 int in[MAXN + 5][MAXK + 5];
 28 
 29 int spfa()
 30 {
 31     queue<co> q;
 32     co start;
 33     start.now = 1;
 34     start.cost = 0;
 35     q.push(start);
 36     in[1][0] = true;
 37     priority_queue<int, vector<int>, greater<int> > pq;
 38     pq.push(INF);
 39     while (!q.empty())
 40     {
 41         co tmp = q.front();
 42         q.pop();
 43         int now = tmp.now;
 44         int cost = tmp.cost;
 45         if (now == n)
 46         {
 47             pq.push(d[n][cost]);
 48         }
 49         in[now][cost] = false;
 50         for (int i = 0; i < G[now].size(); i++)
 51         {
 52             if (cost + G[now][i].toll <= k && 
 53                 d[now][cost] + G[now][i].len < d[G[now][i].to][cost + G[now][i].toll])
 54             {
 55                 d[G[now][i].to][cost + G[now][i].toll] = d[now][cost] + G[now][i].len;
 56                 if (d[G[now][i].to][cost + G[now][i].toll] >= pq.top())
 57                     continue;
 58                 if (!in[G[now][i].to][cost + G[now][i].toll])
 59                 {
 60                     in[G[now][i].to][cost + G[now][i].toll] = true;
 61                     co son;
 62                     son.now = G[now][i].to;
 63                     son.cost = cost + G[tmp.now][i].toll;
 64                     q.push(son);
 65                 }
 66             }
 67         }
 68     }
 69     int minL = INF;
 70     for (int i = 0; i <= k; i++)
 71     {
 72         minL = min(minL, d[n][i]);
 73     }
 74     return minL;
 75 }
 76 
 77 int main()
 78 {
 79     cin >> k >> n >> m;
 80     for (int i = 0; i < m; i++)
 81     {
 82         cin >> s >> t >> l >> T;
 83         node tmp;
 84         tmp.to = t;
 85         tmp.len = l;
 86         tmp.toll = T;
 87         if (s != t)
 88             G[s].push_back(tmp);
 89     }
 90     memset(d, 0x3f, sizeof(d));
 91     for (int i = 0; i <= k; i++)
 92     {
 93         d[1][i] = 0;
 94     }
 95     int minLen = spfa();
 96     if (minLen >= INF)
 97         puts("-1");
 98     else
 99         cout << minLen << endl;
100     return 0;
101 }

 最优性剪枝总结:

1. 从初始状态到当前状态的代价已经不小于目前找到的最优解,则剪枝。

2. 预测一下从当前状态到解的状态至少要花的代价W,如果W加上到达当前状态时已经花费的代价,必然不小于目前找到的最优解,则剪枝。

3. 如果到达某个状态A时,发现前面曾经也到达过A,且前面那次到达A所花代价更少,则剪枝。这要求记录到目前为止到达状态A时所能取得的最小代价。

原文地址:https://www.cnblogs.com/wangyiming/p/6347814.html