ZOJ 3794 Greedy Driver 最短路

Greedy Driver

Time Limit: 2 Seconds      Memory Limit: 65536 KB

Edward is a truck driver of a big company. His daily work is driving a truck from one city to another. Recently he got a long distance driving work, so he may be needed to add fuel to his truck on the way. His boss gives him a fuel card, he can use the card anytime at any fuel station and add any amount of fuel. He does not spend any money when he uses the card. He noticed that there are some cities where he could sell fuel. The greedy driver Edward want to make some money while he doing this work. And this is his plan:

There are N cities on his map and numbered from 1 to N, he need to drive from city 1 to city N to finish this task. Driving from one city to another need fuel cost too. There are some of the cities has fuel station, he could use his fuel card at these cities. Notice his truck has a fuel tank capacity C and it could not exceed the capacity when add fuel. At the beginning, he is at city 1 and he has a full tank.

At some cities he could sell any amount of fuel he has, and the prices at each city maybe different. Since he does not want to be found, he sell the fuel at most once totally. Under the premise of driving to city N finally, he wants to make the maximal money.

Input

There are multiple test cases. For each test case:

The first line contains three integer N (1 ≤ N ≤ 1000), M (1 ≤ M ≤ 100000), C(1 ≤ C ≤ 30000), N is the number of cities, M is the number of roads, please notice that the roads is single-way, and C is the fuel tank capacity.

The after M lines describe the roads, each line has three integers A, B (1 ≤ A, BN), L (1 ≤ L ≤ 30000). That means the fuel cost from city A to city B is L.

Then a single line contain one integer P (0 ≤ PN), it is the number of cities which has a fuel station.

The after single line contains P integers, each integer pi (1 ≤ piN) is a city number means this city has a fuel station.

Then a single line contain one integer Q (0 ≤ QN), it is the number of cities which he could sell fuel.

Each of the after Q lines contains two integers qi (1 ≤ qiN), vi (1 ≤ vi ≤ 30000), means the price at city qi is vi. If he sell one unit of fuel, he will get vi money.

There is a blank line between every two cases.

Process to the end of input.

Output

One line for each test case. The maximal money he could make while doing this task, or -1 if he could not reach city N.

Sample Input
5 6 10
1 2 4
1 4 1
4 3 1
2 5 1
4 5 2
3 2 1
1
3
1
2 2
Sample Output
16

Author: LI, Huang

Source: ZOJ Monthly, June 2014

题目链接:ZOJ 3794 Greedy Driver

题目大意:

给你n个点,m条有向边,其中1为起点,n为终点,给你一辆可装汽油容量为C的车,一开始装满汽油,走每条路汽油都有损耗,其中有p个点可以免费把汽油加满,q个点可以兜售单价为v的汽油任意。问,在只能兜售一次的情况下能得到的最大价值,如果不能达到终点则输出-1。

题目分析:

先从起点跑一次spfa,计算出走到每个点时能剩下汽油的最大值maxf[i],一遍spfa后,如果终点走不到,直接输出-1。

接下来再从终点顺着反边反着跑一边spfa,得到每个点到终点的最少花费d[i]。那么最终答案就是max(sell[i] * (maxf[i] - d[i])),其中sell[i]为单价,i为所有的可以卖的城市。

PS:就这么点内容我想了N久, 果然是够渣的T    T

//ZOJ 3794 Greedy Driver
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define clear(A, X) memset(A, X, sizeof A)
const int oo = 0x3f3f3f3f;
const int maxN = 1005;
const int maxE = 1000000;
struct Edge{
    int v, n, c;
};
Edge edge[maxE], E[maxE];
int adj[maxN], cntE, Adj[maxN];
int Q[maxE], inq[maxN], head, tail;
int d[maxN], maxf[maxN];
int fuel[maxN], city[maxN], sell[maxN], fuel_cnt, sell_cnt;
int n, m, C;
void addedge(int u, int v, int c){
    edge[cntE].v = v; edge[cntE].c = c; edge[cntE].n = adj[u]; adj[u] = cntE++;
    E[cntE].v = u; E[cntE].c = c; E[cntE].n = Adj[v]; Adj[v] = cntE++;
}
void spfa(){
    clear(maxf, -1);
    clear(inq, 0);
    head = tail = 0;
    maxf[1] = C;
    Q[tail++] = 1;
    while(head != tail){
        int u = Q[head++];
        inq[u] = 0;
        for(int i = adj[u]; ~i; i = edge[i].n){
            int v = edge[i].v;
            if(maxf[v] < maxf[u] - edge[i].c){
                maxf[v] = maxf[u] - edge[i].c;
                if(fuel[v]) maxf[v] = C;
                if(!inq[v]){
                    Q[tail++] = v;
                    inq[v] = 1;
                }
            }
        }
    }
}
void SPFA(){
    clear(d, oo);
    clear(inq, 0);
    head = tail = 0;
    d[n] = 0;
    Q[tail++] = n;
    while(head != tail){
        int u = Q[head++];
        inq[u] = 0;
        for(int i = Adj[u]; ~i; i = E[i].n){
            int v = E[i].v;
            if(d[v] > d[u] + E[i].c){
                d[v] = d[u] + E[i].c;
                if(fuel[v]) d[v] = 0;
                if(!inq[v]){
                    Q[tail++] = v;
                    inq[v] = 1;
                }
            }
        }
    }
}
void work(){
    int u, v, c, ans = 0;
    clear(adj, -1);
    clear(Adj, -1);
    clear(fuel, 0);
    cntE = 0;
    for(int i = 0; i < m; ++i){
        scanf("%d%d%d", &u, &v, &c);
        addedge(u, v, c);
    }
    scanf("%d", &fuel_cnt);
    for(int i = 1; i <= fuel_cnt; ++i){
        scanf("%d", &u);
        fuel[u] = 1;
    }
    scanf("%d", &sell_cnt);
    for(int i = 1; i <= sell_cnt; ++i) scanf("%d%d", &city[i], &sell[i]);
    spfa();
    if(maxf[n] == -1){
        printf("-1\n");
        return;
    }
    SPFA();
    for(int i = 1; i <= sell_cnt; ++i){
        int have = maxf[city[i]] - d[city[i]];
        if(have > 0 && have * sell[i] > ans) ans = have * sell[i];
    }
    printf("%d\n", ans);
}
int main(){
    while(~scanf("%d%d%d", &n, &m, &C)) work();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值