首页 > 代码库 > 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 }