首页 > 代码库 > ZOJ3794 Greedy Driver [BFS]
ZOJ3794 Greedy Driver [BFS]
题目地址: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3794
题目描述:
N个城市,M条有向边。要从城市1开车到城市N,中途可以加油,也可以倒卖一次油,问最多能赚多少钱。
油箱容量是C。N个城市中有P个城市(p1, p2…)可以任意免费加油; 有Q个城市(q1,q2…),可以卖油(价格为pri1,pri2…),但全程只能在一座城市卖一次油;每条边都会消耗一定的油。在一开始,油箱是满的。如果能从城市1到达城市N,输出最多可以赚的钱,否则输出-1。
解题思路:
一开始读错题还在考虑遍历城市的问题,后来发现不用遍历每座城市。。于是问题就很简单了。因为只能卖一次油,状态也很好保存。
每个节点(城市)维护一下几个值:
isReachable - 是否能从城市1走到
isPassable – 在装满油箱时,能否从这个城市走到城市N
leastUnit – 从这个城市走到城市N,一开始至少要装多少油
pendingMaxUnit – 走过这座城市时,在还没有卖过油的状态下,油箱最多能剩多少油
soldMaxEarn – 走过这座城市时,已经曾经卖过一次油,并且当前的剩余油量不低于leastUnit的条件下,赚到最多的钱
isFuelStation – 是否可以加油
canSellFuel – 是否可以卖油
price – 如果可以卖油,每单位的油价
首先从城市N反向跑一个BFS,标记isPassable并计算出leastUnit。
再从城市1跑一个BFS,计算出isReachable,pendingMaxUnit,soldMaxEarn。
源代码:
1 //zoj3794_zzy_2014.07.15_AC_graph BFS_DP 2 #include <iostream> 3 #include <queue> 4 5 using namespace std; 6 7 class Edge 8 { 9 public: 10 Edge(int v, int c, Edge *p): vid(v), cost(c), next(p) {} 11 int vid, cost; 12 Edge *next; 13 }; 14 15 class Vertex 16 { 17 public: 18 Vertex() {} 19 bool isReachable; //can through the beginning to this vertex with capacity C. 20 bool isPassable; //can through this vertex to the end with the capacity C. 21 int leastUnit; //from this vertex to the end, need at least leastUnit unit fuel. leastUnit can be larger than maximum capacity C. 22 int pendingMaxUnit; //when pass this vertex and never sold fuel, the maximum left unit of fuel. This can be less than leastUnit. 23 int soldMaxEarn; //when pass this vertex and sold fuel and left fuel no less than leastUnit, the maximum money earned. 24 bool isFuelStation; 25 bool canSellFuel; 26 int price; 27 Edge *ep; 28 Edge *bep; 29 }; 30 31 class GreedyDriver 32 { 33 public: 34 GreedyDriver(int n, int m, int c): N(n), M(m), C(c) { 35 for(int idx = 1; idx <= N; ++idx) { 36 graph[idx].isReachable = false; 37 graph[idx].isPassable = false; 38 graph[idx].leastUnit = -1; 39 graph[idx].pendingMaxUnit = -1; 40 graph[idx].soldMaxEarn = -1; 41 graph[idx].isFuelStation = false; 42 graph[idx].canSellFuel = false; 43 graph[idx].price = 0; 44 graph[idx].ep = NULL; 45 graph[idx].bep = NULL; 46 } 47 } 48 ~GreedyDriver() { 49 for(int idx = 1; idx <= N; ++idx) { 50 Edge *p = graph[idx].ep; 51 while(p != NULL) { 52 Edge *q = p; 53 p = p -> next; 54 delete q; 55 } 56 } 57 } 58 void construct(); 59 void solve(); 60 int ans(); 61 private: 62 int N,M,C; 63 Vertex graph[1001]; 64 void iniLeastUnit(); 65 void BFS(); 66 }; 67 68 void GreedyDriver::construct() 69 { 70 for(int idx = 1; idx <= M; ++idx) { 71 int s, t, l; 72 cin >> s >> t >> l; 73 Edge *p = new Edge(t, l, graph[s].ep); 74 graph[s].ep = p; 75 Edge *q = new Edge(s, l, graph[t].bep); 76 graph[t].bep = q; 77 } 78 int P; 79 cin >> P; 80 while(P--) { 81 int vid; 82 cin >> vid; 83 graph[vid].isFuelStation = true; 84 } 85 int Q; 86 cin >> Q; 87 while(Q--) { 88 int vid, pri; 89 cin >> vid >> pri; 90 graph[vid].canSellFuel = true; 91 graph[vid].price = pri; 92 } 93 } 94 95 int GreedyDriver::ans() 96 { 97 if(graph[N].isReachable == false) 98 return -1; 99 int maxEarn = 0;100 for(int idx = 1; idx <= N; ++idx) {101 if(graph[idx].isReachable && graph[idx].isPassable && graph[idx].soldMaxEarn > maxEarn)102 maxEarn = graph[idx].soldMaxEarn;103 }104 return maxEarn;105 }106 107 void GreedyDriver::iniLeastUnit()108 {109 bool inQueue[1001];110 for(int idx = 1; idx <= N; ++idx)111 inQueue[idx] = false;112 graph[N].leastUnit = 0;113 queue<int> Q;114 while(!Q.empty()) Q.pop();115 Q.push(N);116 inQueue[N] = true;117 while(!Q.empty()) {118 int fid = Q.front();119 Q.pop();120 inQueue[fid] = false;121 int fLeastUnit = graph[fid].isFuelStation ? 0 : graph[fid].leastUnit;122 Edge *p = graph[fid].bep;123 while(p != NULL) {124 int sid = p -> vid;125 int sLeastUnit = fLeastUnit + p -> cost;126 if(graph[sid].leastUnit == -1 || graph[sid].leastUnit > sLeastUnit) {127 graph[sid].leastUnit = sLeastUnit;128 if(graph[sid].leastUnit <= C)129 graph[sid].isPassable = true;130 if(graph[sid].isPassable && inQueue[sid] == false) {131 Q.push(sid);132 inQueue[sid] = true;133 }134 }135 p = p-> next;136 }137 }138 }139 140 void GreedyDriver::BFS()141 {142 bool inQueue[1001];143 for(int idx = 1; idx <= N; ++idx)144 inQueue[idx] = false;145 if(graph[1].isPassable == false)146 return;147 graph[1].isReachable = true;148 graph[1].pendingMaxUnit = C;149 if(graph[1].canSellFuel) {150 if(graph[1].isFuelStation)151 graph[1].soldMaxEarn = C * graph[1].price;152 else if(graph[1].pendingMaxUnit > graph[1].leastUnit)153 graph[1].soldMaxEarn = (graph[1].pendingMaxUnit - graph[1].leastUnit) * graph[1].price;154 }155 queue<int> Q;156 while(!Q.empty()) Q.pop();157 Q.push(1);158 inQueue[1] = true;159 while(!Q.empty()) {160 int fid = Q.front();161 Q.pop();162 inQueue[fid] = false;163 Edge *p = graph[fid].ep;164 while(p != NULL) {165 int sid = p -> vid;166 if(graph[sid].isPassable) {167 if(graph[fid].pendingMaxUnit - (p -> cost) >= (graph[sid].isFuelStation ? 0 : graph[sid].leastUnit)) {168 if(graph[sid].isReachable == false) {169 Q.push(sid);170 inQueue[sid] = true;171 }172 graph[sid].isReachable = true;173 if(graph[sid].isFuelStation)174 graph[sid].pendingMaxUnit = C;175 else {176 if(graph[fid].pendingMaxUnit - (p -> cost) > graph[sid].pendingMaxUnit) {177 graph[sid].pendingMaxUnit = graph[fid].pendingMaxUnit - (p -> cost);178 if(inQueue[sid] == false)179 Q.push(sid);180 inQueue[sid] = true;181 }182 }183 if(graph[sid].canSellFuel) {184 if(graph[sid].isFuelStation)185 graph[sid].soldMaxEarn = C * graph[sid].price;186 else if(graph[sid].pendingMaxUnit > graph[sid].leastUnit &&187 (graph[sid].pendingMaxUnit - graph[sid].leastUnit) * graph[sid].price > graph[sid].soldMaxEarn)188 graph[sid].soldMaxEarn = (graph[sid].pendingMaxUnit - graph[sid].leastUnit) * graph[sid].price;189 }190 }191 }192 p = p-> next;193 }194 }195 }196 197 void GreedyDriver::solve()198 {199 graph[1].isReachable = true;200 graph[N].isPassable = true;201 iniLeastUnit();202 BFS();203 }204 205 int main()206 {207 int n,m,c;208 while(cin >> n >> m >> c) {209 GreedyDriver *gd = new GreedyDriver(n, m, c);210 gd -> construct();211 gd -> solve();212 cout << gd -> ans() << endl;213 delete gd;214 }215 return 0;216 }