读题可发现,对于每一个由地点和油量组成的二元状态,我们只有2种决策:
1.加油。
2.去往下一个能去的目的地。
最开始的时候其实不知道怎么确定加油的多少。但是看看数据规模。。。直接上暴力的记忆化bfs吧!
决策2的状态转移很好办,决策一的就暴力的让它每一次加一单位油,然后看作新状态。
关于算法的正确性,容易证明,使用优先队列的BFS中,每个状态(或者说阶段)第一次出队时即为该状态的最小代价。
具体在这道题中,当终点T的某个状态第一次被取出时,即为最优答案.
(我不会说我第一次写没有用记忆化然后TLE了)
1 #include <cstdio>
2 #include <algorithm>
3 #include <queue>
4 #include <vector>
5 #include <cstring>
6 #include <iostream>
7 using namespace std;
8 const int MAXN = 1000 + 20;
9 const int INF = 0x3f3f3f3f;
10
11 int N, M, Q;
12 int C, S, T;
13 int cc[MAXN], d[MAXN][110];
14
15 struct edge
16 {
17 int to, dis;
18 edge(int v = 0, int c = 0) : to(v), dis(c) {}
19 };
20
21 vector<edge> g[MAXN];
22
23 struct P
24 {
25 int city, fuel, cost;
26 bool operator >(const P &x) const{
27 return cost > x.cost;
28 }
29 }ans;
30
31 inline bool solve()
32 {
33 priority_queue<P, vector<P>, greater<P> > q;
34
35 d[S][0] = 0;
36 P s;
37 s.city = S, s.fuel = 0, s.cost = 0;
38 q.push(s);
39 while(!q.empty())
40 {
41 P p = q.top(); q.pop();
42 if(p.city == T)
43 {
44 ans = p; return true;
45 }
46 if(p.fuel < C && d[p.city][p.fuel + 1] > d[p.city][p.fuel] + cc[p.city])
47 {
48 d[p.city][p.fuel + 1] = d[p.city][p.fuel] + cc[p.city];
49 P nxt = p;
50 nxt.fuel++;
51 nxt.cost += cc[p.city];
52 q.push(nxt);
53 }
54
55 int u = p.city;
56 for(int i = 0; i < (int) g[u].size(); i++)
57 {
58 const edge &e = g[u][i];
59 if(e.dis <= p.fuel && d[e.to][p.fuel - e.dis] > p.cost)
60 {
61 d[e.to][p.fuel - e.dis] = p.cost;
62 P nxt = p;
63 nxt.fuel -= e.dis;
64 nxt.city = e.to;
65 q.push(nxt);
66 }
67 }
68 }
69 return false;
70 }
71
72 int main()
73 {
74 //freopen("11367.txt", "r", stdin);
75 cin>>N>>M;
76 for(int i = 0; i < N; i++)
77 scanf("%d", &cc[i]);
78
79 int u, v, c;
80 for(int i = 1; i <= M; i++)
81 {
82 scanf("%d%d%d", &u, &v, &c);
83 g[u].push_back(edge(v, c));
84 g[v].push_back(edge(u, c));
85 }
86
87 cin>>Q;
88 while(Q--)
89 {
90 cin>>C>>S>>T;
91 memset(d, 0x3f, sizeof(d));
92 if(solve()) cout<<ans.cost<<endl;
93 else puts("impossible");
94 }
95 return 0;
96 }